So a bit more news.  Good news!

The attached screen shot from the RM CAN monitor shows 3 messages.  The first 
message with ID 0x298 is a PDO message which is the status from the device.  
Second byte lower 4 bits represents what it says the outputs are set to.  The 
top 4 bits are what it was commanded to do with those outputs.

The next message is the NMT heartbeat from node 0x718 which is my device.  The 
0x05 says its alive and NMT_OPERATIONAL which means it's allowed to send PDO 
messages with device information.

Finally we have the PDO message 0x318 which is 'from' the Pi4 LinuxCNC 
interfaced to the Lawicel CANUSB as /dev/ttyUSB0 using the Python pySerial 
library.

Notice the 0x04 data byte.  That's the bit which is connected to the Mist 
ON/OFF button and that bit switches on a relay in my little device.

Also attached is the python file.  I put the HAL stuff in the custom.hal file.

I click on the checkbox on the Axis interface and the mist relay clicks on.  
Click again to remove the checkmark and the mist relay goes off.  And the PDO 
message on the monitor goes from 00 to 04 to 00.

This example is the sending from AXIS via pySerial onto the CAN bus.  Next step 
will be to present a switch press that is read by my device and shows up in the 
first byte of the 0x298 PDO.  And I guess I'll add a heartbeat from LinuxCNC..

Lots more to do but at this point I can control relays via CAN bus.

John Dammeyer

> -----Original Message-----
> From: John Dammeyer [mailto:jo...@autoartisans.com]
> Sent: September-10-21 10:11 AM
> To: 'Enhanced Machine Controller (EMC)'
> Subject: Re: [Emc-users] Serial Port access
> 
> Hi Andy,
> 
> The output below shows CANopen PDO message #2 (0x300) to ID 0x18, 1 byte, 
> alternating between 0x01 and 0x00 being issued once
> per second.
> 
> pi@raspberrypi:~/projects/python $ python TestSerial.py
> Sent CAN message with relay value = t318101
> Sent CAN message with relay value = t318100
> Sent CAN message with relay value = t318101
> Sent CAN message with relay value = t318100
> Sent CAN message with relay value = t318101
> 
> The little module shown in that photo I posted last time is connected to a 
> pneumatic valve on Output #1.  It clicks ON and OFF once
> per second.   The code is running as a Python Command line program on a 
> standard Raspian distro.  I'll bring out the Pi4 with
> LinuxCNC and take a look at linking into the HAL file.
> 
> IMHO the Python serial is very clumsy for dealing with serial with all the 
> format and .encode parameters for simple character strings.
> The source code is attached.
> 
> John Dammeyer
> 
> > From: andy pugh [mailto:bodge...@gmail.com]
> > On Thu, 9 Sept 2021 at 05:31, John Dammeyer < 
> > <mailto:jo...@autoartisans.com> jo...@autoartisans.com> wrote:
> > > I've been reading
> > >  <http://linuxcnc.org/docs/2.4/html/hal_comp.html> 
> > > http://linuxcnc.org/docs/2.4/html/hal_comp.html
> >
> > For this application I think that a Python userspace component using
> > Pyserial is probably the easier approach.
> >
> >  <http://linuxcnc.org/docs/2.8/html/hal/halmodule.html> 
> > http://linuxcnc.org/docs/2.8/html/hal/halmodule.html
> >
> > --
> > atp
#!/usr/bin/python

# Project LinuxCNC Python CANUSB Serial Port control derived from:
# 
https://forum.linuxcnc.org/10-advanced-configuration/538-controlling-coolant-w-serial-port?start=0
# User: mozmck  (Moses McKnight)

# This application has been modified to use the Lawicel CANUSB treated as a USB 
serial port
# sending out CAN messages in the CANopen format.

# Version 0.1 10SEP21
# Written by 
#   John Dammeyer
#   jo...@autoartisans.com

import hal
import time, serial

# *** Issue this command from the terminal
#sudo apt-get install python-serial

# The serial-relays.py needs to be in the config directory for your mill.
# For example:  '/home/jerrybaca/emc2/configs/harborfrieghtmill' 
# Don't forget to sudo chmod +x serial-relays.py

# *** Next Place the following lines into one of the Post HAL files.
#     custom.hal is probably a good enough place.
#loadusr -Wn serial-relays ./serial-relays.py 

#net coolant-mist <= iocontrol.0.coolant-mist
#net coolant-flood <= iocontrol.0.coolant-flood

#net coolant-mist => serial-relays.relay1C
#net coolant-flood => serial-relays.relay1D
# *** End of HAL file instructions.

# --- Global Variables ---
h = hal.component("serial-relays")
h.newpin("relay1A", hal.HAL_BIT, hal.HAL_IN)
h.newpin("relay1B", hal.HAL_BIT, hal.HAL_IN)
h.newpin("relay1C", hal.HAL_BIT, hal.HAL_IN)
h.newpin("relay1D", hal.HAL_BIT, hal.HAL_IN)
h.newpin("relay1E", hal.HAL_BIT, hal.HAL_IN)
h.newpin("relay1F", hal.HAL_BIT, hal.HAL_IN)
h.newpin("relay1G", hal.HAL_BIT, hal.HAL_IN)
h.newpin("relay1H", hal.HAL_BIT, hal.HAL_IN)
h.ready()


# Serial stuff, change the serial port address by changing /dev/ttyS0 or COMx 
(for Windows)
# For USB based Serial dongles that use FTDI hardware /dev/ttyUSB0 is often the 
default.
# USB can be set for 115200 baud as long as the target hardware can support 
that since
# it doesn't really delay the LinuxCNC side.
ser = serial.Serial('/dev/ttyUSB0', 115200, bytesize=8, parity='N', stopbits=1, 
timeout=0, xonxoff=0, rtscts=0)

# Create some Global variables for readability
PDO = 0x300     # Process Data Object #2
NodeID = 0x18   # Device Node ID (0x01..0x7F)
PDO_ID = ''     # The character string that holds the OR operation of the PDO+ID
RelayImage = 0  # No relays set yet.
CANopenPDO_2_Msg = ''  # For reporting what we send and so we don't have to 
recreate it each time.
TempStr = ""    # global so we can print what was sent.

# Individual Relay State values
rA = 0
rB = 0
rC = 0
rD = 0
rE = 0
rF = 0
rG = 0
rH = 0

# --- Methods ---

# Function to send data to CANUSB dongle.  
# Parameters:
#   r is relayimage placed into first byte of PDO message.
# Outputs:
#   Sends CANopenn PDO_2 message to CANUSB.
# Future Enhancements:
#   Pass PDO #, Node ID #, Array of bytes, Number of valid bytes.
def Send_PDO_2(r):
    global CANopenPDO_2_Msg      # the message without the data.
    global TempStr
    # Now empty the Rx Buffer for sample program we don't look at received 
messages.
    while ser.inWaiting():
        ser.reset_input_buffer()  #discard input for now.
     
    ser.write(CANopenPDO_2_Msg.encode('utf-8'))  # send PDO 3xx to node 0x18 
with 1 byte
    # Format bit image to two hex characters
    TempStr = "{0:0{1}X}".format(r,2)
    ser.write(TempStr.encode('utf-8'))
    ser.write('\r'.encode('utf-8'))     # Tell CANUSB to send message with <CR> 
character.

# Function to update local PDO RelayImage
# Parameters:
#   r is which relay to switch (1..8) 
#      does not validate relay # to see if in range.
#   level is TRUE or FALSE for relay ON or OFF.
# Modifies:
#   Global RelayImage bitmap of relay values
#
def Update_Relays(r, level):
    global RelayImage         # if this isn't here then the OR operation fails 
with unitialized variable.
    # Create the text value of the relay image.
    bitmask = 1 << (r-1)    # Select which relay to switch ON.
    if level == True:
        RelayImage = (RelayImage | bitmask)
    else:
        RelayImage = (RelayImage &  ~bitmask)

# --- Mainline loop ---
try:
    # Create text value of CAN Standard ID => PDO + Node ID and Message Length 
of 1
    PDO_ID = "{0:0{1}X}".format(PDO+NodeID,3)
    CANopenPDO_2_Msg = 't' + PDO_ID + '1'

    # Initialize CANUSB dongle
    ser.write('C\r'.encode('utf-8'))    # Close first
    ser.write('F\r'.encode('utf-8'))    # Clear Error Flags by reading them
    ser.write('S5\r'.encode('utf-8'))   # set 250kbps
    ser.write('O\r'.encode('utf-8'))    # Open CANUSB for communication.
    Send_PDO_2(RelayImage)                # Update PDO with default value.
    # Main Loop
    while 1:
        relayChanged = False            # If a relay has changed then this 
flags it.
        
        if (rA != h.relay1A):           # Test the HAL pin
            rA = h.relay1A              # if it's changed then update our image.
            Update_Relays(1, rA)        # Update the Byte Image too
            relayChanged = True         # And flag it so a CANopen PDO will be 
sent.
        if (rB != h.relay1B):
            rB = h.relay1B
            Update_Relays(2, rB)
            relayChanged = True
        if (rC != h.relay1C):
            rC = h.relay1C
            Update_Relays(3, rC)
            relayChanged = True
        if (rD != h.relay1D):
            rD = h.relay1D
            Update_Relays(4, rD)
            relayChanged = True
             
        if (relayChanged):              # Did a relay change?
            Send_PDO_2(RelayImage)        # Update PDO.
            

except KeyboardInterrupt:
    raise SystemExit
_______________________________________________
Emc-users mailing list
Emc-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/emc-users

Reply via email to