Shop OBEX P1 Docs P2 Docs Learn Events
Difficulty acquiring and using data from Applied Motion RS232 motor controller — Parallax Forums

Difficulty acquiring and using data from Applied Motion RS232 motor controller

imaradiostarimaradiostar Posts: 3
edited 2016-09-02 15:44 in Propeller 1
I'm new to writing spin code and I'm already in it up to my eyeballs. I am following the work of a coworker and thus far I've been able to tweak his code for my needs. I've written some code to give direct control of one of our servos (an applied motion TSM23S) to simplify the operation of our device.

I'm assuming a pro will see some error immediately but this code sortof works. By pressing the "stop" key the propeller sends a command to the servo that should report (via ASCII) the servo's current encoder position. I have the prop storing this info as a byte array and spitting it out to the serial terminal. If I can make this work reliably I'd like to be able to use the encoder position elsewhere in the code.

The problem is that the output isn't reliable. After initiating a move or encoder zero it takes quite a few "stop" keypresses before the correct encoder position is displayed in the debug terminal. I don't know if it's failing to read or print the value correctly and I don't know how to determine the difference. I have verified using the Applied Motion tool that the servo controller is receiving and responding to the messages. Can you please help me?

Jamie (code snippets below, unsure of correct code posting syntax on this forum so I'll use italics- EDIT- found it and fixed it!)
VAR
  long SMstack[20],WPstack[20]
  long iLay, nLay
  long SLD_LimLeft, SLD_LimRight
  byte SM_ID, WP_ID
  byte SlidePos[25]

...(other code here)

PRI Traverse_Adjust

  repeat
    if pin.In(JOG_L_PIN)==0                 'Jog left
      fds.str(DEBUG,string(CR,"Jogging to the left",CR))
      fds.str(SLD,string("SJ",CR))            'stop jog
      fds.str(SLD,string("JS0.10",CR))        'jog speed set
      fds.str(SLD,string("DI-1000",CR))       'direction set
      fds.str(SLD,string("CJ",CR))            'commence jog
      time.Pause(250)
    elseif pin.In (JOG_R_PIN)==0            'Jog right
      fds.str(DEBUG,string(CR,"Jogging to the right",CR))
      fds.str(SLD,string("SJ",CR))           'stop jog
      fds.str(SLD,string("JS0.10",CR))       'jog speed set
      fds.str(SLD,string("DI1000",CR))       'direction set
      fds.str(SLD,string("CJ",CR))           'commence jog
      time.Pause(250)
    elseif pin.In (JOG_STOP)==0             'Stops jog
      fds.str(SLD,string("SJ",CR))
      fds.str(DEBUG,string(CR,"Stopping!",CR))
      time.Pause(20)
      fds.str(SLD,string("EP",CR))          'requests current encoder pos from TSM23S
      time.Pause(50)
      dio.StrIn(SLD,@SlidePos)              'stores string to byte array
      time.Pause(50)
      dio.str(DEBUG,@SlidePos)              'sends string to debug terminal
      fds.str(DEBUG,string(CR))
      time.Pause(250) 
    elseif pin.In(SET_ZERO)==0              'Set current position to EP=0
      fds.str(SLD,string("SJ",CR))          'Stops motor jog
      time.Pause(20)
      fds.str(SLD,string("EP0",CR))         'Sends 1st command to make current position zero
      time.Pause(20)
      fds.str(SLD,string("SP0",CR))         'Sends 2nd command to make current position zero
      time.Pause(250)
    else

      time.Pause(50)  

Comments

  • Do you have a link to the document that explains the serial protocol? As programmers, we're individuals, hence we don't all think alike. I'd be willing to bang out a bit of code to show you how I would approach the problem which may cause you to see something in your own code.

    For me it's tricky to deal with snippets. Can you post an archive of your project so others can compile on their ends?
  • Here's a link to the host command reference from Applied Motion.

    I'm happy to post my code but I've since made a giant mess of things in an effort to fix issues. It is becoming clear that I don't yet know how to manage cogs and use them simultaneously and that could be a problem. I was about to start breaking out and testing the individual parts of my code.

    I've enclosed an archive. By commenting out portions of it the various aspects seem to work but as it applies to controlling the traverse (serial port called SLD) I can't seem to share control between the adjustment and main processes. This is part of a cable winding machine. Initial attempts were highly automated but didn't give enough flexibility. It seems that the ability to stop and manually adjust will be a huge help and more important than counting the number of layers wound or continuing unassisted.

    The complication is that we are using external motor controllers that don't automatically report their position. My initial question relates to being able to query the position, store and interpret the ASCII string, and eventually use that string to make control choices.

    Jamie

  • JonnyMacJonnyMac Posts: 9,104
    edited 2016-09-02 23:17
    I'm a big believer in building large, complex systems out of a lot of small, easy-to-deal-with parts. If I were in your shoes I would create a couple of methods that allow me to set or request a parameter from the driver. Once those are working then a system can be assembled around them.

    Here's an idea to get you going. If you can get these working then building your system should be a little easier.
    pub set_value(p_cmd, value)
    
    '' Set value in drive
    '' -- p_cmd is pointer to 2-letter parameter string
    '' -- value is new setting
    
      comx.str(p_cmd)
      comx.dec(value)
      comx.tx(13)
    
    
    pub get_value(p_cmd, p_buf) | len, c, idx, sign, value
    
    '' Get value from drive
    '' -- p_cmd is pointer to 2-letter parameter string
    '' -- p_buf is pointer to buffer for receiving response
    ''    * 16 or more bytes recommended
    
      comx.rxflush                                                  ' clear rx buffers
      bytefill(p_buf, 0, BUF_SIZE)                                  
    
      comx.str(p_cmd)                                               ' request parameter value
      comx.tx(13)
    
      len := 0
    
      repeat
        c := comx.rxtime(COM_TIME_OUT)
        if (c => 0)
          byte[p_buf][len++] := c
        else
          quit
    
      ' verify response
    
      comerror := false                                             ' clear global coms error flag
    
      repeat idx from 0 to 1
        if (byte[p_buf][idx] <> byte[p_cmd][idx])                   ' mismatch?
          comerror := true
          return 0
    
      if (byte[p_buf][2] <> "=")
        comerror := true   
        return 0
    
      sign  := 1
      value := 0
      p_buf += 3                                                    ' skip past = sign
    
      ' check for sign
      
      c := byte[p_buf]
      if (c == "-")
        sign := -1
        p_buf++
    
      ' extract value
    
      repeat
        c := byte[p_buf++]
        if ((c => "0") and (c =< "9"))
          value := value * 10 + (c - "0")
        else
          quit
    
      return sign * value
    

  • Thanks, I think I get the basic idea of what you're doing. I think building working sections of the code and combining them is the way to go but I came into this project following other work and hadn't had the luxury of a clean-sheet redesign. It seems like that's how things often go in R&D. If knew more about how to use different cogs I think I would assign a cog for key input and debounce then one for each function or something like that. That way it should always be a responsive system.

    I've searched the internet for "comx" and I'm not familiar with it. Is it a serial object? Can you point me to a manual or page for it?

    It seems the various different serial objects have very different ways of being used. This job requires quite a few serial ports, some of which aren't even implemented yet. Would the method you show above be translatable to the four port serial object that I'm using?

    Jamie
  • kwinnkwinn Posts: 8,697
    The x in comx is just a number assigned to that comm, not a specific object. The four port object can be used for pretty much anything the single serial object is used for, and I use it often. The only real difference is that you have to specify the port number.
  • The reference to comx was, for me, an instantiation of FullDuplexSerial -- I don't [yet] use the multi-port code.
Sign In or Register to comment.