Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HAL driver for CAN #589

Open
luminize opened this Issue Apr 25, 2015 · 186 comments

Comments

@luminize
Copy link
Member

luminize commented Apr 25, 2015

As a subissue of #586 I'll try to get history, questions, contemplations, answers, tips and all what passes collected into this issue.

During the process I want to write down "the stuff" so when we release it into the wild we have the docs also ready to go. I'll do that in a dedicated branch can-in-machinekit here: https://github.com/luminize/machinekit-docs/tree/can-in-machinekit

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Apr 27, 2015

yes, let's make this thread the focus of 'all things CAN/CANopen and machinekit', possibly forking off sub-issues as needed.

Let's start with taking stock of resources:

Linux basic CAN I/O support:

Linux CAN - software tools:

  • the can-utils package has commandline tools for SocketCAN configuration and use. NB: in jessie, wheezy needs building from source.
  • the python-can package has Python bindings for basic CAN message I/O

basic SocketCAN programming examples:

CANopen-related tools ( the stack ontop of raw CAN messages):

CANOpen - options for embedded platforms:

Linux-based tools:

  • wireshark can perfectly decode CAN and CANopen messages on real and virtual (aka 'vcan') interfaces. Strongly recommended.

Useful documents:

Timing and Performance:

Other sources of information:

  • stackoverflow.com has useful Q&A on CANopen (keywords can canopen), for instance on PDO mapping

CAN Interface hardware I have used:

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Apr 27, 2015

In terms of results, I would see the following (number=priority)

  • (1) a CANOpen master HAL module, supporting several devices with different profiles
  • (1) a simple CANopen slave module for linux, must be able to connect to the above (eg over a virtual can interface). Might export HAL pins too. Primary use case: intra-HAL regression testing.
  • (2) a CANOpen slave HAL module (maybe the same as the previous item). This would enable wrapping machinekit as a CANopen-controlled device (servo drive, pin I/O etc)
  • (2) an embedded CANopen client on a popular platform like Arduino, as an example to start from.

Here's a note on how a master might be structured in terms of the HAL API

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Apr 27, 2015

Testing fieldbus components: here's a sketch how this could be done .

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Apr 28, 2015

maybe we should invite https://github.com/jgeisler0303 over? I see mutual benefits

@ghost

This comment has been minimized.

Copy link

ghost commented Apr 29, 2015

Hello from CANopenNode.

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Apr 29, 2015

oh hi! welcome to the caravan!

@ghost

This comment has been minimized.

Copy link

ghost commented May 2, 2015

May I suggest Arduino Due. It has SAM3X8E ARM Cortex-M3 CPU. It is much stronger than 8-bit AVR on arduino uno. And it already has CAN. No problem to connect a motor, do some path calculation and run CANopen smoothly. And it seems, somebody wrote a driver for that processor for CANopenNode already.
I didn't investigate any further, but I think, there is no sense to use Arduino uno. I think, It is not strong enough to drive a decent motor.

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented May 2, 2015

you're right, at these prices it doesnt make much sense to use a uno, and interfacing will actually be easier since no mcp2515 is needed, just a mcp2551 or equivalent

I'll see what can be had off fleabay ;)

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented May 3, 2015

setup tips:

For development I use virtualbox (under OSX, but shouldnt matter)
for playing with socketCAN it's useful to have at least a virtual can interface (vcanX)
here's a gist for vcan setup: https://gist.github.com/mhaberler/a9af7ef9f885113795cc

in case you have an USBtin it is also easy to use from a VM:

on OSX, I have a USB device filter 'USBtin' with Vendor 04d8 and Product 0000a so the USBtin is attached to the VM as soon as I plug it in, it comes up as /dev/ttyACM0

here's a gist how I configured wheezy so USBtin at /dev/ttyACM0 comes up as can0 at 1Mbit:
https://gist.github.com/mhaberler/eef30dd73aa7b326b8b3

for using wireshark, dont forget to add your userid to the netdev group - otherwise permission problems

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented May 3, 2015

One of my goals is to keep the docs up to date with my efforts.
For those interested in setting up development for socketcan, wireshark and the stuff @mhaberler mentions above:
https://github.com/luminize/machinekit-docs/blob/can-in-machinekit/machinekit-documentation/developing/CAN-developing.asciidoc
and
https://github.com/luminize/machinekit-docs/blob/can-in-machinekit/machinekit-documentation/setting-up/CAN-developing-setup.asciidoc

documents are work in progress

@amitgoradia

This comment has been minimized.

Copy link

amitgoradia commented May 4, 2015

This is also a nice resource for a canopen ds402 implementation.
https://github.com/golems/socanmatic/

They have an EDS parser written in python: https://github.com/golems/socanmatic/blob/master/canmatc

regards,
-amit

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented May 7, 2015

I'm setting up my USBtins with socketcan.
http://www.fischl.de/usbtin/linux_can_socketcan/

Where there's also mention of can for Rpi
http://elinux.org/RPi_CANBus

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented May 7, 2015

this is essentially SPI to SPI-Canbus-Controller-to-Canbus which every board/SoC with an SPI interface can do, pretty much like the AVR Canbus shield

so it's the 'ok, CAN not natively available, let's fallback onto SPI' solution which would work with just about every board, at the cost/inflexibility introduced by the CAN controller chip (typically this one: http://www.microchip.com/wwwproducts/devices.aspx?dDocName=en010406)

@ghost

This comment has been minimized.

Copy link

ghost commented May 8, 2015

Is there any other SPI CAN controller with more than six filters? Comfortable CANopen device needs more than six input filters. If CAN module does not have enough filters, then microcontroller must receive all traffic via SPI. It may be quite a heavy load for 8-bit device.

A long ago I was using 8-bit PIC18F458. I tested it at 1Mbps with full CAN bus load and it worked fine. But microcontroller has integrated CAN and there is some inline assembly in receive interrupt.
See http://sourceforge.net/projects/canopennode/files/canopennode/ , version 0.9, CANopDriver.c

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented May 8, 2015

which side are you talking about?

For the HAL/mk master side we can assume there is a given controller, either on-chip like with the Sitara's, or as a card, like a PCI card for a PC, so I dont see much flexibility here - I would prefer to stay out of custom hardware as much as possible, and too early - that makes adoption so much more difficult

for the client side - where would the need for larger filter sets come from ? I thought a client just filters on its node id and that is it?

@ghost

This comment has been minimized.

Copy link

ghost commented May 8, 2015

Master side should not be a problem. It's fast enough.

CANopen CAN message ID's:

typedef enum{
     CO_CAN_ID_NMT_SERVICE       = 0x000,   /**< 0x000, Network management */
     CO_CAN_ID_SYNC              = 0x080,   /**< 0x080, Synchronous message */
     CO_CAN_ID_EMERGENCY         = 0x080,   /**< 0x080, Emergency messages (+nodeID) */
     CO_CAN_ID_TIME_STAMP        = 0x100,   /**< 0x100, Time stamp message */
     CO_CAN_ID_TPDO_1            = 0x180,   /**< 0x180, Default TPDO1 (+nodeID) */
     CO_CAN_ID_RPDO_1            = 0x200,   /**< 0x200, Default RPDO1 (+nodeID) */
     CO_CAN_ID_TPDO_2            = 0x280,   /**< 0x280, Default TPDO2 (+nodeID) */
     CO_CAN_ID_RPDO_2            = 0x300,   /**< 0x300, Default RPDO2 (+nodeID) */
     CO_CAN_ID_TPDO_3            = 0x380,   /**< 0x380, Default TPDO3 (+nodeID) */
     CO_CAN_ID_RPDO_3            = 0x400,   /**< 0x400, Default RPDO3 (+nodeID) */
     CO_CAN_ID_TPDO_4            = 0x480,   /**< 0x480, Default TPDO4 (+nodeID) */
     CO_CAN_ID_RPDO_4            = 0x500,   /**< 0x500, Default RPDO5 (+nodeID) */
     CO_CAN_ID_TSDO              = 0x580,   /**< 0x580, SDO response from server (+nodeID) */
     CO_CAN_ID_RSDO              = 0x600,   /**< 0x600, SDO request from client (+nodeID) */
     CO_CAN_ID_HEARTBEAT         = 0x700    /**< 0x700, Heartbeat message */
}CO_Default_CAN_ID_t;

Average CANopen client should accept:
NMT, SYNC, 4xRPDO, 1xRSDO, 4xHeartbeat (for monitoring)

6 receive messages should go too:
NMT, SYNC, 2xRPDO, 1xRSDO, 1xHeartbeat (in case, master has problems, client should shut-down actuators)

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented May 9, 2015

The more I read about CANopen, the more I'm realising that this fieldbus bus is highly configurable. Master-slave, multi-master, syncing, hearbeats, event change driven... It's going to be all about the messaging.

The TPDO and RPDO's are in my laymen terms the registers that will determine for a node which message to send, and for a node to which message on the bus to listen to.

Nodes can listen to the master, or to other nodes. Extrapolating: it's a subscriber model. having one foot in userland, the other foot in realtime or userland

The way I see it, is that Machinekit is not limited to a realtime timing. So messages can come from nodes at undetermined times. Polling will give a lot of overhead and is discouraged.

Reading the data from the bus: the HAL driver should always listen to the bus, and put the messages from the bus in a ring buffer. Components can than act on the messages
Writing to the bus could be done in 2 ways:

  • There should be a second ringbuffer acting as master/slave that can put messages gathered from hal-canopen-components onto the physical bus. This will make one "HAL CANopen node" which has to act as would any other node with respect to collisions of data etc (master/slave does not matter yet).
  • Each hal-canopen-component should be a full fledged node, message triggered by a thread. It should have access to the bus, acting in the way as would any other CANopen node wrt collision and conformity.

I think the 2nd option would be quite "heavy" and since every hal-canopen-component becomes a node, this will go at the cost of the available nodes on the bus.

reading on, so opinion might change.
Thoughts?

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented May 10, 2015

those communication patterns are certainly possible in full generality, but maybe on average just very simple patterns are used

the right abstraction will likely depend on the use case, so maybe thinking about two hypothetic devices at both ends of the spectrum is a good starting point - like a dumb I/O expander to wiggle/read pins (not time critical), and at the other end some super-duper motion subsystem which can move several motors in a coordinated fashion, maybe even based on a segment-level API (likely time critical)

the primary object to deal with IMO is the device dictionary, which is a collection of variables with name, id, type, and purpose (very similar to pins). The messaging is mostly subordinate to that in the sense that it helps establish a comms path, and more or less peek and poke values from/to this dictionary on a per-device basis.

now a particular HAL component/application might use just a small fraction of the dictionary, so an obvious task of a comp startup would be to select dict entries to talk to - which would wind up in pins, and the messages going back and forth serve to synchronize the device values and HAL pins

that simple view probably is enough for the dumb I/O expander case and then some (NB Fernandos canopen.comp use this model).

in the intelligent drive use case you'd likely have more work than just peek/poke type operations, like downloading segments, synchronizing their execution, and monitoring their execution status. Even there, I'm unsure a generalized messaging API to the CANbus will be helpful outside the handling component. What might be needed is a segment-level API between motion and the CANopen component for segments - no way to do this through pins

A ringbuffer or queue for that matter helps storing values until receiving components can act upon them, in case they cannot do so right away; but at least in the dumb I/O expander model, and likely the drive use case the HAL-side component could very well just do synchronous I/O

so overall my idea would be: keep CAN comms internal to the component for now, and strive for doing the dumb I/O expander case first (NB this can used with a motor drive - where commanded position values are poked to, and actual position values are peeked from)

once we get this right, we can look into such a segment-level API.

before that, I guess we need to get session management (NMT), heartbeating, comms errors (emergency?) and the like right; looks to me this layer will be pretty much the same for all use cases

I wonder what @pJanez @amitgoradia @fmederos @alueger and Uwe's take is on this?

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented May 10, 2015

My first component will be a component, attached to the CAN bus, and when i send a can message I want to see a HAL pin wiggle.

Regardless of the way to implement things we should ponder whether a HAL-CANopen-slave or HAL-CANopen-master are on the "normal" RT servo-thread. Meaning

  • that either all HAL components listen directly on the bus and thus are not depending on the servo thread
  • or the ring buffer listens independent on servo thread, and is the Schnittstelle between RT and non-RT (I see the CAN bus itself as non-RT, might be wrong :) )

all other stuff will come later, but the nature of the bus itself is in a very important thing to understand for me.

@githubuser0xFFFF

This comment has been minimized.

Copy link

githubuser0xFFFF commented May 10, 2015

Hi, it's me, Uwe

Before I give an advice, I would like to ask a question. If I use a BeagleBone Black with PRU for control of 3 stepper motors for a coordinated movement plus 2 output ports to control of 2 heaters - how does the machinekit HAL talk to the 3 stepper motors and how does it talk to the I/O ports?

If I replace the BeagleBone Black with 3 CANopen DS402 Motion Controllers and 1 CANopen DS401 I/O device for the 2 outputs, does something change for the machinekit HAL? I do not have in depth knowledge of the machinekit HAL yet, to have an idea, what is different now. I would assume nothing. CANopen creates a local image of the remote CANopen process data and you talk to the CANopen drives, as if they are locally attached to your control unit, that runs machinekit. Normally it is not necessary to care about any CANopen communication details, if you have a proper abstraction.

In our CANopen software we have for example a CDS402DriveDevice class. This class has an API to execute movements and read drive status, position... If you use this class, you do not need to care about any CANopen communication details, because it all runs behind the scenes.

So at the moment, I'm not sure, what is the difference between a locally attached stepper drive and a remotely attached CANopen device?

Uwe

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented May 10, 2015

Uwe - the way things stand now the interface between motion and hardware of any shape or form is like so (completely platform-independent)

  • joint commanded position values are generated each servo cycle, and output in the axis.N.motor-pos-cmd pins by the motion component
  • the actual positions are read back via the axis.N.motor-pos-fb pins
  • the difference - called following error - of each joint is reflected in axis.N.f-error

now what is connected to this depends on the hardware, but usually it's a stepgen which pretty much works like a servo loop (it gets a commanded position and yields an actual position), or it is a PID loop

you will find examples for either under configs/ - in the 'simulator' configs pid loops are used and the 'motors' are simulated by ddt components

now for the difference between pid/stepgen and CANopen attachment:

  • in Fernando's canopen.comp - CANopen over RTnet: none. He just pumps out cmd-pos to the CANopen device each servo cycle.
  • in Bas' future component: that remains to be seen - if we can retain the current 'one commanded position value per cycle' OR we need to turn down the servo rate to not overwhelm the bus or device (NOT good) OR we find some other API (like segment-level into the tp) to reduce the data rate

BTW none of this has any bearing on the platform: if BB or Rpi or x86. Also, the semantics of the stepgen component is the same if doing PRU stepping, FPGA stepping on a mesanet card or software stepping using the stepgen component.

@fmederos

This comment has been minimized.

Copy link

fmederos commented May 10, 2015

Bas,
Writing a component that directly access a CANOpen bus is one very big
task, if that is what you meant. Anyway you should not need to do so!

I'm not sure about canopennode, but CANfestival does all the bus
arbitration so a CANOpen HAL component just needs to pass data to and from
CANfestival.

CANfestival uses its own real-time for bus timings, this runs independent
from LCNC/MKIT's real-time. Sure the routines accessing the bus uses their
own buffers as you say.

Maybe canopennode provides this functionality or more, I did not look at it
long enough...
El 10/05/2015 09:36, "Bas de Bruijn" notifications@github.com escribió:

My first component will be a component, attached to the CAN bus, and when
i send a can message I want to see a HAL pin wiggle.

Regardless of the way to implement things we should ponder whether a
HAL-CANopen-slave or HAL-CANopen-master are on the "normal" RT
servo-thread. Meaning

  • that either all HAL components listen directly on the bus and thus
    are not depending on the servo thread
  • or the ring buffer listens independent on servo thread, and is the
    Schnittstelle between RT and non-RT (I see the CAN bus itself as non-RT,
    might be wrong :) )

all other stuff will come later, but the nature of the bus itself is in a
very important thing to understand for me.


Reply to this email directly or view it on GitHub
#589 (comment)
.

@amitgoradia

This comment has been minimized.

Copy link

amitgoradia commented May 11, 2015

Michael,
First we need to analyse the bus bandwidth available in order to decide on a strategy for dumping motor position every millisecond or adopt a segments queue approach. We also need to identify the maximum drives that can be addressed from one CANBus channel to decide the approach.

An interesting test done by someone on CANBus bandwidth : http://electronics.stackexchange.com/questions/121329/whats-the-maximum-can-bus-frame-message-rate-at-125-kbit-s
It is mentioned that they are able to reach the theoretical maximum bus bandwidth!! Which is about 954 frames/sec (8byte frames). But with arbitrary data they can see worst case times of 850 fps. This is done at 125kBps bus speed.

Extrapolating at 1Mbps, we can transmit 6.8 frames/msec. Lowering the payload byte count is not going to affect this theoretical maximum by a great amount (maybe 1.5x higher can be achieved by reducing the payload bytes).

Consider regular mill with 3 axes. Consider Cyclic Servo Positioning (CSP) mode, i.e., the one where we dump millisecond level position points to the drives. The following data needs to be exchanged at the servo rate (every msec):

  1. position for axis 1 (controller to drive)
  2. encoder for axis 1 (drive to controller)
  3. position for axis 2
  4. encoder for axis2
  5. position for axis3
  6. encoder for axis3
  7. Sync pulse for applying the axis position sent by the bus. (as a part of the CANOpen standard).

So, we need 7 frames/msec minimum to keep things going which is theoretically possible (which shorter payload frames as SYNC may not need any payload and position and encoder are 4 byte values). Also, to my knowledge CANOpen uses 11 but identifier frames as opposed to 29 bit frames so that will also give us a little more bandwidth. We also need to account for heartbeat message and NMT messages which are a part of DS 301.

Add in one more axis or a discrete IO device to the mix and we hit the boundary of what is possible with a single CANBus in CSP mode. Move the non-synchronized devices to another bus and we are back the feasible realm.

CANOpen is a very lightweight and configurable protocol for industrial bus communications. No wonder it forms the basis of COE (CANOpen over Ethercat).

Part 2. Segments API:
This approach requires a fundamental change to the way things are done in LinuxCNC where the Linux PC is considered supreme and needs to do all the work (in some cases generate the high speed pulse train too!! ). As we see the limitation of the bus is for the controller to be able to send points every msec to the drives. In a segments approach, we model the output of the motion planner as a polynomial equation with coefficients.
A linear move can be defined as follows:
startpoint: X0, Y0, Z0, A0, B0, C0, U0, V0 ,W0
endpoint: X1, Y1, Z1, A1, B1, C1, U1, V1, W1
a polynomial: p = at^3 + b_t^2 + c_t + d where p is the position along the path as a function of time.
t_final- assume the polynomial holds from t=0 to t= t_final.

t varies from 0 to t_final. p varies from 0 to 1 but need not cover the entire range. when p=0 the path is at the startpoint provided, and p=1 path is at endpoint provided in the command.

Position of the axis is calculated using the equations:
p = at^3 + b_t^2 + c_t + d
x = X0_p +X1_(1-p)

Now by specifying 23 parameters, we can basically cover a large line segment spanning 100's of milliseconds. All we need to now specify is the time tick on a per msec basis which is done by the SYNC command in CANOpen.
With this approach, each drive will be sent its startpoint (X0), its endpoint (X1), polynomial coefficients (a,b,c,d) and the final time(t_final). Further, the parameters (a,b,c,d,t_final) are common to all the drives and can be sent out as a broadcast to the Axes. Then sending a SYNC command will just cycle the trajectory.

NOTE: I still have to readup on the segment level API offered by CANOpen which should be a part of DS402.

My initial thoughts: First try CSP with limited number of axes. This will avoid fiddling with the trajectory planner and allow us to test the CANBus implementation first.

-amit

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented May 11, 2015

Amit - that's exactly what I was thinking when Andreas came up with the idea first time around: we might swamp the bus. That's why Claudio uses several CAN interfaces in his zedboard setup.

There is one fundamental question which I dont have an answer to, assuming a segment-level API; maybe you folks with more experience with fieldbus drives can answer this - it is: where is the kinematics handled, and how does that impact what is being sent to the drive?

With servo-rate quantisation host-side, we're in infinitesimal territory - it is safe to assume the 1mS increments can be approached through a line. Plus the drive being a low-pass: we get a curve.

BUT: if we lower the rate, this assumption might not hold anymore in connection with a non-trivial kinematics:

let us assume a non-trivial kins, like a scissor kinematics, and the interpreter sending a cartesian straight move. This will translate into a fairly arbitrary cuve per joint over time, and the way things are done right now this curve is just handled by sampling into very short lines.

Now sending such a curve to the drives - I see two approaches:

  • how it is currently done - sample at high rate, meaning bus load problem
  • something you hinted at: transforming this curve into a polynomial equation and sending the parameters to the drive for execution.

My question: how is this usually done? what is the flow? does one go down all the way to samples, then generate the polynomial params from that sample set? does one push the issue uplevel and only send polynomial equations from the interpreter downwards? if so - the parameters would not survive a nontrivial kinematics unchanged.

the drives obviously would operate in joint space (short of a DeltaTau I've seen none which can do kins on-drive).

Or is it just that industrial applications of such drives are all trivkins anyway and I'm pushing a non-issue?

@jpmoniz

This comment has been minimized.

Copy link

jpmoniz commented May 11, 2015

@mhaberler @amitgoradia

Guys,

Keep in mind that just because a feature may be apart of DS402 does not mean OEM's implement them. Some choose to implement basic features. If i look at the drive I have. They have only implemented basic torque and velocity . Others choose to implement things like interpolated position mode. It may be worthwhile surveying the most popular DS402 operation modes supported. Then decide on what work may be required.

@ghost

This comment has been minimized.

Copy link

ghost commented May 11, 2015

There is no need to handle CAN messages directly. Application should use variables from object dictionary (controlWord, statusWord, TargetPosition, PositionPoints, ActualPosition, etc.). It is then configurable by CANopen, what are the rules for exchanging the values. CANopenNode and CANfestival (as explained @fmenderos) use this approach.

I think, CANopen drives must be autonomous and they only accept points and controlWord from master(trajectory planner, Machinekit.). Drive must read its encoder and handle PID loop or count steps on its own. So there is no need for real-time encoder information on the bus. Drive sends back only status word (one bit gives information, if following error is inside window or not). It usually sends actual position, but it does not need to be real-time, it can be sent after each tenth sync message only. It is only for information.
That way there is no problem to drive three or more axis complex joint in one millisecond interval. CAN FD will later enable even more data to transfer.
Another way is to use polynomial, which could further reduce traffic. In trapezoidal movement, there are three points necessary to get exact movement, in jerk-free trapezoidal, there are seven points. In complex joint system there could be some smart function, which splits trajectory into segments of proper length, I guess.

I think, Machinekit should be first capable to use first approach (send points each millisecond), because it is simpler and some commercial drives use this approach (like this ).
EPOS 2, on the other side, uses polynomial approach, as I know.
However, it is not standardised in CiA402, how points are used.
We may think polynomial approach as an upgrade in next phase, where we could be capable to implement some CANopen drives too.

The first approach is also compatible with "Cyclic position mode". I think, most users support that mode. Michael, please verify that.

@ghost

This comment has been minimized.

Copy link

ghost commented May 11, 2015

If CiA402 drive implements only torque and velocity mode (frequency inverter), then it is probably not suitable for servo positioning.

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented May 11, 2015

to all: thanks for the discussion/answers/questions. For me at this moment this is still a few steps away regarding implementation, but investigating further I need to understand the boundaries for my future blunder prevention.

Last week I got into some discussion with @mhaberler and @alueger and what struck me regarding the DS402 PVT profile was that points on a curve can be defined for different time intervals. We looked at section 8 (page 54) of this document http://www.a-m-c.com/download/sw/dw300_3-0-3/CAN_Manual300_3-0-3.pdf

At the risk of derailing the discussion...
When we get to segments (i know this is still too early :) ) and more difficult applications maybe we need to temporarily forget the fixed time approach, and consider the allowable path deviation instead.
Example:
Making an arc with trivial kinematics, it makes no sense to generate a lot of data for motion for the y-axis motor when we're at the (X=0, Y=R) position. Because there we can let the node of the y-axis do the interpolation.
When the arc progresses the frequency of points to interpolate of the y-axis will increase, and at the same time for the x-axis will decrease.

I'm only guessing here, but that would mean that we can use less bandwidth as long as we know when not to send a new position at a specified point in time, simply because it is not needed from the point of accuracy. But that could be a future planning thing.

@fmederos @pJanez , first thing for me now is that I will explore the available functionality wrt communication, NMT, messages etc. First thing is to just activate and read and write date to and from a device. Probably not even with machinekit yet.

@githubuser0xFFFF

This comment has been minimized.

Copy link

githubuser0xFFFF commented May 12, 2015

We use CANopen drives from Maxon, ELMO, Trinamic, Nanotec and Kocomotion. The following table shows a small matrix of the supported operation modes that are relevant (Profile Velocity Mode PVM, Velocity Mode VM, Interpolated Position Mode IPM. Cyclic Synchronous Position Mode CSVM):

Drive PVM VM IPM CSVM
EPOS 1 1 1 0
Trinamic 1 1 0 0
Nanotec 0 1 1 0
Kocomotion 1 0 0 0
ELMO 1 0 1 1

If we use the CANopen drives as dumb drives and simply pump out speeds in a 1ms intervall, than we could use the PVM or VM for setting the Velocity. For this mode a controlword (16 Bit), the velocity (32 bit) and the statusword (16Bit) is required. The controlword + velocity is mapped into an RPDO and the statusword is mapped into a TPDO. Additionally we need an global 8Bit sync message so that the new velocity is executed synchronously by all drives. So we have:

RPDO (controlword + velocity) = 48 Bit Data + 47 Bit Frame = 95 Bit
TPDO (statusword) = 16 Bit Data + 47 Bit Frame = 63 Bit

Sync-Msg: = 8 Bit Data + 47 Bit Frame = 55 Bit

If we running the bus with 1MBit and a update intervall of 1 ms, then we can theoretically control:

(1000 Bit/ms - 55 Bit Sync) / 158 Bit per Drive = 5,98 = 5 Drives (ca. 80% bus load)

If the update intervall is increased to 1.5 ms or 2 ms, control of more drives would be possible.

@githubuser0xFFFF

This comment has been minimized.

Copy link

githubuser0xFFFF commented Jan 3, 2016

hi @gcurteanu Thanks for sharing - it is really impressive what you have created so far - great work.

@claudiolorini: CANopen messages have 11b CAN IDs.

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Jan 3, 2016

@gcurteanu - congratulations! that warps us ahead quite a bit!

Actually I would think this should work on the BB just as well with the RTCAN driver loaded.

I'm focusing on a ROS-related presentation right now on Jan 29 as does @luminize and @cdsteinkuehler - we want to have something to show -- expect significantly increased attention thereafter ;)

@gcurteanu

This comment has been minimized.

Copy link

gcurteanu commented Jan 4, 2016

Thanks. I guess it should work on anything as long as RTCAN / CanFestival can run on it. Haven't tried playing with my BB for such uses, but might give it a try at some point. Actually, I have something else in mind for BB & MK.

Anyway, did some updates to bring the code to a relatively functional state for my use, in particular error handling. It's now functional and detects errors from NMT/HeartBeat/EMCY, faulting as soon as detected (instant for NMT/EMCY or 1 HB interval). Recovery from fault is automatic on a low->high enable transition, and depending on the error cause it will either try to clear the fault via a 402 fault reset (if only EMCY present), or via a complete device reset (reconfiguration from scratch automatic under 302, as done during startup).
Since fault resetting does take a bit (not really RT), it's allowed to proceed only for a small time (5ms, will make it configurable). If fault reset fails or takes too long, component goes back to fault and enable can be retried (ex: component hard faults, try enable, device reset+reconfig is done but takes too long, component faults on timeout. Second enable knows it's a internal (component) fault and clears that bringing the reconfigured device online). Not sure if this can be handled in another way for RT applications.

As far as component performance goes, I see the update function spiking to 5-6us (sometimes higher), and this is directly a result of the CanFestival PDO code (saw a mention somewhere that's sub-optimal for a large number of PDOs and I tend to agree).

@CANopenNode

This comment has been minimized.

Copy link

CANopenNode commented Jan 4, 2016

Hi Guys,

CANopenNode port to Linux is now somehow finished and usable. It is a CANopen device with SDO and NMT master. It is based on SocketCAN. Critical code runs in nonblocking RT thread. All code is in C and it is written in a object oriented way. It was tested on Debian based Linux PC, Beaglebone black and Raspberry PI.

It is possible to build any type of CANopen device in top of it and/or it can be used as a master with command line interface to CANopen. Theoretically (if joined with Machinekit) it could also turn Machinekit into a CANopen device.

For more info and some getting started see:
https://github.com/CANopenNode/CANopenSocket

@ul-gh

This comment has been minimized.

Copy link

ul-gh commented Feb 16, 2016

Hi, I finally made some progress with my machine setup which is a Beagle Bone Black with Machinekit plus three SEW MDX61B AC servo inverters with CANopen bus positioning.

First of all, closing the speed control loop via bus signal with a 1ms cycle time might work with severely reduced loop gain, but i realised that this is impractical if the servo at peak torque accelerates from zero to 3000 RPM in actually less than 20ms.

Fortunately, the drive controllers that feature fieldbus positioning modes seem to have sufficient controller dynamics, including speed- and acceleration feed-forward-control, already implemented internally in order to compensate for each joint friction and acceleration forces. Thus, in the case of trivial kinematics and assumed constant moving masses, an accurate and fast position command response should be no problem.

My SEW MDX61B drives are no exception. While all drive parameters can be configured via reasonably well-documented drive-specific extensions of the CANopen object directory via SDO transfer, I used the PC configuration tool for basic configuration.

The rest of the setup is very simple. The drives implement the basic DS-301 CANopen profile, but they do feature cyclically and linearly interpolated position mode (configuration setting called "bus ramp" or "BUSRAMPE" in the manual) and hard synchronisation to a 1-ms-granular CANopen sync telegram with an interpolation interval of 1ms, 5ms or 10ms configurable.

All that was then really necessary for my setup was sending a single CANopen NMT telegram to trigger a once-only communication reset and a second one to put the drives into operational state. That again by default means automatic transmission of cyclic absolute position feedback telegrams via individual (COB-ID derived by configured drive ID) 32-bit TxPDOs (+16-bit status word), triggered by reception of the bus-wide CANopen sync telegram. At that point, each drive also automatically and simultaneously puts into action a new position setpoint telegram, received in the bus time before.

I am right now trying to switch from positioning experiments via BASH script + socket-can command line tools to using the rt-can API of Xenomai and the Machinekit HAL components.

What would be needed has basicly been said already in this thread:

  1. Read 3x 32-bit TxPDO buffered (received before) position feedback
    telegrams from the RT-CAN socket, possibly do little/big endian
    conversion, scaling and check for drive error flag
  2. Feed these three joint position feedback values directly
    to the HAL motion component and let it calculate the new resulting
    position command values resulting from the trajectory and kinematics
  3. Send 3x 32-bit RxPDOs to the drive controllers via RT-CAN socket
  4. Send 1x 0-bit empty (ID only) Sync telegram to the RT-CAN socket
    which triggers simultaneous motion of the joint drives with the
    updated position setpoints.

My programming experience is rather limited, and I hope that I can directly use the Xenomai API from a inside the HAL component. Then there is not much left to do aside from possibly writing everything up for documentation with which I could help. Plus providing a working drive configuration file for the MDX61B drives.

A question that I have would be if the HAL motion component automatically calculates the tracking error (difference in position setpoint and feedback value) and reduces the feed rate accordingly if one of the joints can't keep up, or if it is only possible to trigger an error if the tracking error exceeds a set hard maximum value.

@magnifikus

This comment has been minimized.

Copy link

magnifikus commented Jun 14, 2016

Just want to join the discussion as i will start "creating" some solution for my needs.
my scenario is 3 groschopp can open drives i want to control via machinekit.

my constraints are:
raspberry/zynq based controller (either mcp2515 or zynq peripheral as can controller)
control of the drives via DSP402 interpolation (as far as i can tell i can only define the next position, no queue)
update rate kinda sucks, as the drives specs only allow updates every 4,8ms and are limited to 500kbaud

my current status:
canopennode is running and i can access SDO's and configure heartbeats.

next steps:
find a way to exchange pdos from machinekit maybe i just use an fpga and do some "fixed heavy lifting" there. will keep you updated

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Jun 15, 2016

it would certainly be valuable to have a working CANopen master

can we have a look?

@magnifikus

This comment has been minimized.

Copy link

magnifikus commented Jun 18, 2016

nothing really done yet, but testing with rt-prempt and cansocket yield horrible results atleast for a rpi1 (testbed only):
socketcan with 250kbaud and external mcp2515
modified cansend that pushes out just a sync message every 5ms with rt scheduling (stack faulting, memlock etc)
priorities: mcp251x irq 52 (usb stuff runs at 51)
mycansend tried 49 and 52 too (no difference)

unloaded system (measured with scope on can otherwise idle can bus): ~200µs jitter
loaded with cat /dev/random > /dev/null: ~200µs jitter too
ping flood from rpi to ethernet (-i 0.01) : jitter goes up to 2-3ms

Crosstest with cyclictest and same ethernet load:
./cyclictest -m -t1 -p 80 -n -i 500 -l 100000
/dev/cpu_dma_latency set to 0us
policy: fifo: loadavg: 0.58 0.22 0.18 1/123 1680
T: 0 ( 1668) P:80 I:500 C: 100000 Min: 19 Act: 29 Avg: 39 Max: 105

i know the setup is not the best fit, but i fear that socketcan is not tool the cyclic pdo stuff.
next to investigate:
a. zynq with the soc stuff, cause the zynqs got integrated can controllers (you just need a phy)
this option is apealing as you can do stuff like sync generation in the fpga
b. not using socketcan but the mcp2515 direct via spi while abusing the filters etc (this is not good for SDO operations etc, maybe you need a 2nd mcp for this stuff via socketcan)
c. dedicated µC that is acting as "lite" can open master (like picnc or fpga based stepgenerator)
d. buying a beaglebone (ohmybudget)

@claudiolorini

This comment has been minimized.

Copy link

claudiolorini commented Jun 18, 2016

For a CANOpen master a Zynq should have enough juice, i suggest to take a look at the MYIR-Z-Turn board, it has already 1 CAN on-board and adding another is rather easy!

For example this is my new toy for the MYIR:
8x insulated CAN + Ethercat + Insulated I + Insulated O

img_9633

img_9640

C.

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Jul 2, 2016

I just saw this on the ROS list and it looks like a viable base for a Canopen HAL driver:

Von: Andreas Bihlmaier via ros-users ros-users@lists.ros.org
Betreff: [ros-users] Announcing: KaCanOpen - An Open Plug&Play CANopen Stack for ROS in Modern C++
Datum: 22. Juni 2016 um 13:56:22 MESZ
An: ros-users@lists.ros.org
Kopie: Andreas Bihlmaier bihlmaier@robodev.eu
Antwort an: Andreas Bihlmaier andreas.bihlmaier@gmx.de, User discussions ros-users@lists.ros.org

tl;dr: You use CANopen devices and ROS? Then checkout: http://wiki.ros.org/kacanopen (Repository: https://github.com/KITmedical/kacanopen)

Dear ROS community,

I'm happy to announce KaCanOpen, a plug&play ROS stack for CANopen devices (motors, remote I/Os, ...) written in modern C++.

KaCanOpen is an easy-to-use CANopen stack, which consists of four parts:

Drivers: A wide range of CAN hardware (USB, PCI, embedded) is supported using different CAN drivers. They have been developed by the CanFestival project. Follow the link for details.
Core: This is a library which implements basic CANopen protocols like NMT, SDO and PDO. As an example, you can easily fetch a value from a device (uploading in CANopen terminology) via core.sdo.upload(node_id, index, subindex). Furthermore, it allows you to register callbacks on certain events or any incoming messages, so one can build arbitrary CANopen nodes (master or slave) using this library.
Master: This library is intended to be used for a master node. It detects all nodes in a CAN network and gives direct access to them via standardized CiA® profiles. For example, on a motor device (profile CiA® 402) you can simply call mymotor.set_entry("Target velocity", 500). A main feature of this library is transparent SDO/PDO access to dictionary entries: By default a value is fetched and set via SDO. But you can also configure PDO mappings, which keep the value up-to-date in background via (much more lightweight) PDO messages. The call itself (mymotor.set_entry("Target velocity", 500)) remains unchanged.
ROS Bridge: This library provides a bridge to a ROS network, which makes KaCanOpen especially interesting for robotics. After setting up the CANopen network, the library can publish slave nodes so they are accessible through ROS messages. Special effort is put into the use of standardized message types which allows interaction with other software from the ROS universe. For example, motors can be operated using JointState messages.
KaCanOpen is designed to make use of modern C++11/14 features and to avoid redundant code on the user side wherever possible. Reusing all the available functionality, a custom node for a custom CANopen device can be written in less than 100 lines of code.

Although, I have the joy to announce KaCanOpen here, most credit goes to Thomas for all the effort he put into it!

Cheers,
Andreas


ros-users mailing list
ros-users@lists.ros.org
http://lists.ros.org/mailman/listinfo/ros-users

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Jul 6, 2016

I gave it a try and think this would be a good base to start from - well written and comprehensible API

key requirement is a c++14 standard compiler, so gcc4.9 or later/clang 3.6 or later does it, so doable for stretch and likely jessie

@sirop

This comment has been minimized.

Copy link

sirop commented Jul 6, 2016

@mhaberler
So what would it be? Event/Time triggered non-RT component?

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented Jul 6, 2016

@mhaberler I've always thought we needed to write something where HAL triggers sending messages like new positions and after that sending the SYNC message. I think that the timing of sending that SYNC signal is very important (as little jitter as possible).
Can we re-use one of the external timing (fd) tricks by having the SYNC signal being sent by the KaCanOpen stack after being triggered by HAL, or by the same signal which triggers the execution of the servo thread in HAL? Or do we still need to interface directly to the hardware from HAL. (do i make sense?)

I guess my question is: Can we re-use the KaCanOpen stack by formally defining a boundary between HAL and the (new) master application, like we do with ROS, while still have some time critical messages (new position messages inside the servo thread time budget, and SYNC jitter "free")?

@mhaberler

This comment has been minimized.

Copy link
Member

mhaberler commented Jul 6, 2016

I think we should address this in stages

  • integrate into the build
  • first, just make it a userland driver which can query and set values, and deposit/retrieve them from HAL pins, but without timing guarantees
  • once we understand the flow better we can investigate how to integrate better into the HAL RT flow
  • yes, eventfd's are an option to do this
@magnifikus

This comment has been minimized.

Copy link

magnifikus commented Aug 22, 2016

back and playing with a zynq board now (the snickerdoodle, got 2x hardware can controllers + more in the fpga if needed).

from my understanding now is, a high level library like kacanopen is superb for configuration but hard to integrate into the hal. but here comes the caveat of canopen, we can preconfigure everything and go into operational with just PDO's that quite easy to work with (discussed before). So a plain implementation using socketcan should be no problem (but still has the socket stuff in between, kacanopen has that too!).

So for syncs and IPM, that should be ideally produced right after the TP Cycle to apply the PDO's send to drives. Downside is, this is also the sampling point for the position feedback. On a live system with servos like i got for example (they got a maximum sync frequency of 4ms) this means:
t=0ms sync
t=0ms+x position-fb is send over can as PDO
t=2ms? position-fb is processed and TP runs
t=2ms+x position-cmd is send over can as PDO
t=4ms sync the drive is applying the position cmd
t=4ms+x as above
t=6ms next tp run like at 2ms
t=8ms drive arrives at position-cmd! thats 6ms after the position-cmd was issued.

this would need a seperate timed thread at the tp rate but 50% shifted in phase to make the syncs as low as possible in jitter (otherwise you had to todo the readings, tp and writings infront of the sync)

so someone with insight in the tp, is this even applicable? i see a distinguish lag here and we should also check the maximum sync frequencies allowed i predict other µC based motor controlls are not better here. (sry its german from the manual of my drives: https://snag.gy/vqtSzh.jpg )

update:
so after playing with PDO's and SYNCS it looks like that SYNC frequencies over 8ms are cause the drive to not syncing internally properly and its starting to jump and vibrate (like over and undershoot, you can also see that on the position feedback). So the 5ms base period is now up to 8ms...

A basic HAL Component producing SYNCS + PDO and also receives PDO is working on dummy can and will be tested tomorrow with the real drive, hard to say how the high base period is affecting the system.

final update2:
i just ceased following the canopen for servos, atleas for this ones with such high delay. Problems are that all internal circuitry seems to be synced to the SYNC Packets that includes all Motorcontrol stages. So i was only able to sync it with 8ms cycle time and even here was the slightest jitter (~100uS) causing vibrations. Another point is that with 8ms cycle time and the delay the drives do overshoot even with jogging and rapid feeds, so it ended in very unstable behavior. Im sure you can fine tune but for me its over.

if you are interested i can provide a hal component that is transmitting pdo,sync and receives pdos for 3 axis but its quite rudimentary and needs work (esp the nonblocking receiving). Its running at 1ms cycle time with an internal counter to perform write, sync, read on different intervals. (also tried 8ms cycle time, but the problem seems to be, that the sync needs to be spaced from pdo's by some 100uS for the controller to be processed without problems, and i dont want to sleep 100uS in the RT-Thead).

if someone is interested in the drives, i got 3, one might have some internal damage now after my sometimes rough tries).

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented Dec 13, 2016

Hi there. I've been busy with the various work related stuff. So not much progress from my side on HAL+CAN, but I've made a robot running from MK, with CANopen motors. The motors are driven with clock/dir signals, but the setup I do thru python-can. Next project I'll also be using MK with CANopen motors.

I came by this today https://github.com/christiansandberg/canopen and http://canopen.readthedocs.io/en/latest/ and I'll be using this for the future. I thought that this might be a useful link to some of you.

Cheers,
Bas

@zhivko

This comment has been minimized.

Copy link

zhivko commented Dec 16, 2016

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented Dec 16, 2016

@nonpostrans

This comment has been minimized.

Copy link

nonpostrans commented Nov 5, 2017

Hi!

I have three PD4-C motors and I am planing to use them in a CNC machine with machine kit that runs on a BBB. Thanks to the work of luminize I was able to write a tiny python script that put the motors in operation and enables them to work in Step/Dir mode. As long there is no proper CANopen implementation for MK I plan to use them with this interface. I don't know much about LinuxCNC so far but I have a question:

How can I trigger a python script for the homing sequence via the GUI? I have no clue how to make the python script talk with LinuxCNC for example to tell the software that the homing sequence is done or automatically stop the job when one motor goes into fault mode?

Thanks,

A.B

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented Nov 5, 2017

@nonpostrans

This comment has been minimized.

Copy link

nonpostrans commented Nov 5, 2017

Of course I could do it the way you describe it. But I think it is a good idea to "glue python with Machinekit". Actually this is what I want because then I can add the switch directly to the motor which means less cables and wires. You can use 6065h (Following Error Window) and 6066h (Following Error Time Out) to check e.g a machine crash or other unnormalties. Would be good to raise a message or something like that in that case.

@alencastre

This comment has been minimized.

Copy link

alencastre commented Apr 25, 2018

Hi,
Do you know if there is a program similar to this but to control the PD2-C motor through USB instead of CAN?

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented Apr 26, 2018

@alencastre not to my knowledge. But you should first read the documentation of your device. https://en.nanotec.com/products/manual/PD2C_USB_EN/pd2c%252Fconfiguration.html/#topic_msq_jwy_fm shows how you can configure your device. So you should be able to get the device in a certain state / configuration.
https://en.nanotec.com/products/manual/PD2C_USB_EN/general%252FVMM.html/ shows you can have the device run a program. But that is not communicating.
Sending messages is not don thru USB.

@DonLabriola

This comment has been minimized.

Copy link

DonLabriola commented Jul 26, 2018

I am looking to add support for this mode of operation to our integrated motors and separate controllers. I have implemented the control code, including the full CANopen stack, so I have a great deal of flexibility in what forward choices can be made to make them work with Machinekit via CANopen. I have been reading through the thread, and in addition to using sync objects, there is an object called the High Resolution Time Stamp Object 1013H, which is the local time in microseconds (32 bit = 71.58 minutes to cycling around). If one device generates this data at a typical ~150ms update rate (TPDO), this same object can be mapped to an RPDO used to keep all of the controllers on the CAN bus in locked speed/time operation. Internally the time is used to first set (if significantly off) the internal high resolution time in the node to match the master, and then the time bases are compared to digitally phase lock the nodes (by periodically adding or removing one count to/from the time count for the local processor) to compensate for differences in clock frequencies. This makes for a smooth, tight synchronization, which does not take up much bandwidth. When tested, it kept the nodes to within a about 40 microseconds of each other (for me one interrupt time cycle). The master node just needs to pull the local time at sending time, and to have the TPDO set as a higher priority address, to help minimize the latency. A little jitter is ignored by the filtering of the digital PLL implementation so only the slower consistent drifts between the crystal frequencies need to be corrected (jitter thus gets filtered out).

I am interested in implementing the proposed 402 interpolated mode where each axis would get updated every few ms with the trajectory shape (spline fit or a Position/velocity/time parameterization).

How does one get involved? What is the current status of Machinekit over CANopen to the drivers?

Thanks,

Don Labriola, QuickSilverControls

@ArcEye ArcEye added this to Wishlist / Future Consideration in Outstanding issues Aug 1, 2018

@luminize

This comment has been minimized.

Copy link
Member Author

luminize commented Aug 4, 2018

@DonLabriola Basically anybody who wants to add something can get involved by providing a PR. Trying to gather people who are willing to test and get momentum helps. It needs somebody to pull the cart. The current status is that there had been experimentation and discussion.

The way most setups work is to send cyclical data each ms for example. And since the bandwidth for multiple motors is limiting in the 1kHz range, there hasn't been a real effort for cyclic sync position/velocity/torque modes.

I have used CANOpen motors for their relative low cost (drive+motor integrated) in a step/dir mode, and provided pulses with a mesanet card (or beaglebone) like with most stepper configuration uses. But the CANOpen part I have used for setup, and from python canopen library

What needs to be done at a glance:

  • a realtime capable driver (a CANOpen master). You don't want to write this from the ground up, so choosing a well supported open source library would be sensible.
  • Needs to interface the CAN hardware of course.
  • a HAL component exposing T/RPDO's on pins.
  • reading and writing the T/RPDO's from the CANOpen master
  • implementation on configuring such a setup

Thoughts?

@ArcEye ArcEye closed this Aug 4, 2018

@ArcEye ArcEye reopened this Aug 4, 2018

@DonLabriola

This comment has been minimized.

Copy link

DonLabriola commented Aug 11, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.