# HG changeset patch # User Laurent Bessard # Date 1367278307 -7200 # Node ID 6963460bfe0fec3d24074f7e24f4320c4eeea652 # Parent 56643934495cb3cdcf96fc4b20e9a2a9ed1bf1b9# Parent ca1c34ff6c10306d4832b4c9264cbe9581facdc2 Merged diff -r ca1c34ff6c10 -r 6963460bfe0f etherlab/ConfigEditor.py --- a/etherlab/ConfigEditor.py Fri Apr 26 13:59:43 2013 +0200 +++ b/etherlab/ConfigEditor.py Tue Apr 30 01:31:47 2013 +0200 @@ -984,10 +984,6 @@ maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy) event.Skip() -def GetModulesTableColnames(): - _ = lambda x : x - return [_("Name"), _("PDO alignment (bits)")] - class LibraryEditorSizer(wx.FlexGridSizer): def __init__(self, parent, module_library, buttons): @@ -1046,16 +1042,30 @@ wx.TR_COLUMN_LINES | wx.TR_HIDE_ROOT | wx.TR_FULL_ROW_HIGHLIGHT) - self.ModulesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DCLICK, - self.OnModulesGridLeftDClick) + self.ModulesGrid.GetMainWindow().Bind(wx.EVT_LEFT_DOWN, + self.OnModulesGridLeftDown) + self.ModulesGrid.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, + self.OnModulesGridBeginLabelEdit) + self.ModulesGrid.Bind(wx.EVT_TREE_END_LABEL_EDIT, + self.OnModulesGridEndLabelEdit) + self.ModulesGrid.GetHeaderWindow().Bind(wx.EVT_MOTION, + self.OnModulesGridHeaderMotion) self.AddWindow(self.ModulesGrid, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT) - for colname, colsize, colalign in zip(GetModulesTableColnames(), - [400, 150], - [wx.ALIGN_LEFT, wx.ALIGN_RIGHT]): - self.ModulesGrid.AddColumn(_(colname), colsize, colalign) + for colname, colsize, colalign in zip( + [_("Name")] + [param_infos["column_label"] + for param, param_infos in + self.ModuleLibrary.MODULES_EXTRA_PARAMS], + [400] + [param_infos["column_size"] + for param, param_infos in + self.ModuleLibrary.MODULES_EXTRA_PARAMS], + [wx.ALIGN_LEFT] + [wx.ALIGN_RIGHT] * len(self.ModuleLibrary.MODULES_EXTRA_PARAMS)): + self.ModulesGrid.AddColumn(_(colname), colsize, colalign, edit=True) self.ModulesGrid.SetMainColumn(0) + + self.CurrentSelectedCol = None + self.LastToolTipCol = None def GetPath(self): return self.ModuleLibrary.GetPath() @@ -1089,7 +1099,10 @@ item = self.ModulesGrid.AppendItem(root, "") self.ModulesGrid.SetItemText(item, module["name"], 0) if module["infos"] is not None: - self.ModulesGrid.SetItemText(item, str(module["infos"]["alignment"]), 1) + for param_idx, (param, param_infos) in enumerate(self.ModuleLibrary.MODULES_EXTRA_PARAMS): + self.ModulesGrid.SetItemText(item, + str(module["infos"][param]), + param_idx + 1) else: self.ModulesGrid.SetItemBackgroundColour(item, wx.LIGHT_GREY) self.ModulesGrid.SetItemPyData(item, module["infos"]) @@ -1143,33 +1156,67 @@ wx.CallAfter(self.RefreshView) event.Skip() - def OnModulesGridLeftDClick(self, event): + def OnModulesGridLeftDown(self, event): item, flags, col = self.ModulesGrid.HitTest(event.GetPosition()) if item.IsOk(): entry_infos = self.ModulesGrid.GetItemPyData(item) - if entry_infos is not None and col == 1: - dialog = wx.TextEntryDialog(self.ParentWindow, - _("Set PDO alignment (bits):"), - _("%s PDO alignment") % self.ModulesGrid.GetItemText(item), - str(entry_infos["alignment"])) + if entry_infos is not None and col > 0: + self.CurrentSelectedCol = col + else: + self.CurrentSelectedCol = None + else: + self.CurrentSelectedCol = None + event.Skip() + + def OnModulesGridBeginLabelEdit(self, event): + item = event.GetItem() + if item.IsOk(): + entry_infos = self.ModulesGrid.GetItemPyData(item) + if entry_infos is not None: + event.Skip() + else: + event.Veto() + else: + event.Veto() + + def OnModulesGridEndLabelEdit(self, event): + item = event.GetItem() + if item.IsOk() and self.CurrentSelectedCol is not None: + entry_infos = self.ModulesGrid.GetItemPyData(item) + if entry_infos is not None and self.CurrentSelectedCol > 0: + param, param_infos = self.ModuleLibrary.MODULES_EXTRA_PARAMS[self.CurrentSelectedCol - 1] + stripped_column_label = param_infos["column_label"].split('(')[0].strip() + try: + self.ModuleLibrary.SetModuleExtraParam( + entry_infos["vendor"], + entry_infos["product_code"], + entry_infos["revision_number"], + param, + int(event.GetLabel())) + wx.CallAfter(self.RefreshModulesGrid) + event.Skip() + except ValueError: + message = wx.MessageDialog(self, + _("Module %s must be an integer!") % stripped_column_label, + _("Error"), wx.OK|wx.ICON_ERROR) + message.ShowModal() + message.Destroy() + event.Veto() + else: + event.Veto() + else: + event.Veto() - if dialog.ShowModal() == wx.ID_OK: - try: - self.ModuleLibrary.SetAlignment( - entry_infos["vendor"], - entry_infos["product_code"], - entry_infos["revision_number"], - int(dialog.GetValue())) - wx.CallAfter(self.RefreshModulesGrid) - except ValueError: - message = wx.MessageDialog(self, - _("Module PDO alignment must be an integer!"), - _("Error"), wx.OK|wx.ICON_ERROR) - message.ShowModal() - message.Destroy() - - dialog.Destroy() - + def OnModulesGridHeaderMotion(self, event): + item, flags, col = self.ModulesGrid.HitTest(event.GetPosition()) + if col != self.LastToolTipCol and self.LastToolTipCol is not None: + self.ModulesGrid.SetToolTip(None) + self.LastToolTipCol = None + if col > 0: + self.LastToolTipCol = col + param, param_infos = self.ModuleLibrary.MODULES_EXTRA_PARAMS[col - 1] + wx.CallAfter(self.ModulesGrid.SetToolTip, + wx.ToolTip(param_infos["description"])) event.Skip() class DatabaseManagementDialog(wx.Dialog): diff -r ca1c34ff6c10 -r 6963460bfe0f etherlab/EthercatCFileGenerator.py --- a/etherlab/EthercatCFileGenerator.py Fri Apr 26 13:59:43 2013 +0200 +++ b/etherlab/EthercatCFileGenerator.py Tue Apr 30 01:31:47 2013 +0200 @@ -201,7 +201,7 @@ slave_pos = (slave_alias, alias[slave_alias]) # Extract slave device informations - device, alignment = self.Controler.GetModuleInfos(type_infos) + device, module_extra_params = self.Controler.GetModuleInfos(type_infos) if device is not None: # Extract slaves variables to be mapped @@ -322,6 +322,11 @@ if slave_variables.get((index, subindex), None) is not None: pdo_mapping_match["matching"] += 1 + if pdo.getFixed() != True: + pdo_mapping_match["matching"] += \ + module_extra_params["max_pdo_size"] - \ + pdo_mapping_match["count"] + elif pdo.getMandatory(): selected_pdos.append(pdo_index) @@ -332,7 +337,9 @@ if exclusion_scope[0]["matching"] > 0: selected_pdos.append(exclusion_scope[0]["index"]) start_excluding_index = 1 - excluded_pdos.extend([pdo["index"] for pdo in exclusion_scope[start_excluding_index:] if PdoAssign or not pdo["assigned"]]) + excluded_pdos.extend([pdo["index"] + for pdo in exclusion_scope[start_excluding_index:] + if PdoAssign or not pdo["assigned"]]) for pdo, pdo_type in ([(pdo, "Inputs") for pdo in device.getTxPdo()] + [(pdo, "Outputs") for pdo in device.getRxPdo()]): @@ -475,7 +482,7 @@ if len(dynamic_pdos[pdo_type]["pdos"]) > 0: pdo = dynamic_pdos[pdo_type]["pdos"][0] - else: + elif module_extra_params["add_pdo"]: while dynamic_pdos[pdo_type]["current_index"] in pdos_index: dynamic_pdos[pdo_type]["current_index"] += 1 if dynamic_pdos[pdo_type]["current_index"] >= dynamic_pdos[pdo_type]["max_index"]: @@ -493,14 +500,16 @@ dynamic_pdos[pdo_type]["sync_manager"]["pdos_number"] += 1 dynamic_pdos[pdo_type]["sync_manager"]["pdos"].append(pdo) dynamic_pdos[pdo_type]["pdos"].append(pdo) + else: + break pdo["entries"].append(" {0x%(index).4x, 0x%(subindex).2x, %(bitlen)d}, /* %(name)s */" % entry_infos) - if entry_infos["bitlen"] < alignment: - print (alignment, entry_infos["bitlen"]) - pdo["entries"].append(" {0x0000, 0x00, %d}, /* None */" % (alignment - entry_infos["bitlen"])) + if entry_infos["bitlen"] < module_extra_params["pdo_alignment"]: + pdo["entries"].append(" {0x0000, 0x00, %d}, /* None */" % ( + module_extra_params["pdo_alignment"] - entry_infos["bitlen"])) pdo["entries_number"] += 1 - if pdo["entries_number"] == 255: + if pdo["entries_number"] == module_extra_params["max_pdo_size"]: dynamic_pdos[pdo_type]["pdos"].pop(0) pdo_offset = 0 diff -r ca1c34ff6c10 -r 6963460bfe0f etherlab/EthercatCIA402Slave.py --- a/etherlab/EthercatCIA402Slave.py Fri Apr 26 13:59:43 2013 +0200 +++ b/etherlab/EthercatCIA402Slave.py Tue Apr 30 01:31:47 2013 +0200 @@ -11,11 +11,14 @@ NODE_VARIABLES = [ ("ControlWord", 0x6040, 0x00, "UINT", "Q"), ("TargetPosition", 0x607a, 0x00, "DINT", "Q"), + ("TargetVelocity", 0x60ff, 0x00, "DINT", "Q"), + ("TargetTorque", 0x6071, 0x00, "INT", "Q"), ("ModesOfOperation", 0x06060, 0x00, "SINT", "Q"), ("StatusWord", 0x6041, 0x00, "UINT", "I"), ("ModesOfOperationDisplay", 0x06061, 0x00, "SINT", "I"), ("ActualPosition", 0x6064, 0x00, "DINT", "I"), - ("ActualVelocity", 0x606C, 0x00, "DINT", "I"), + ("ActualVelocity", 0x606c, 0x00, "DINT", "I"), + ("ActualTorque", 0x6077, 0x00, "INT", "I"), ] DEFAULT_RETRIEVE = " __CIA402Node_%(location)s.axis->%(name)s = *(__CIA402Node_%(location)s.%(name)s);" diff -r ca1c34ff6c10 -r 6963460bfe0f etherlab/EthercatMaster.py --- a/etherlab/EthercatMaster.py Fri Apr 26 13:59:43 2013 +0200 +++ b/etherlab/EthercatMaster.py Tue Apr 30 01:31:47 2013 +0200 @@ -256,7 +256,7 @@ "Ethercat Slave Type", self.GetSlaveTypesLibrary()) if dialog.ShowModal() == wx.ID_OK: type_infos = dialog.GetValueInfos() - device, alignment = self.GetModuleInfos(type_infos) + device, module_extra_params = self.GetModuleInfos(type_infos) if device is not None: if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): ConfNodeType = "EthercatCIA402Slave" @@ -287,7 +287,7 @@ type_infos = slave.getType() if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: return False - device, alignment = self.GetModuleInfos(type_infos) + device, module_extra_params = self.GetModuleInfos(type_infos) if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): return False return True @@ -425,7 +425,7 @@ "product_code": slave["product_code"], "revision_number":slave["revision_number"], } - device, alignment = self.GetModuleInfos(type_infos) + device, module_extra_params = self.GetModuleInfos(type_infos) if device is not None: if HAS_MCL and _EthercatCIA402SlaveCTN.NODE_PROFILE in device.GetProfileNumbers(): CTNType = "EthercatCIA402Slave" @@ -519,7 +519,7 @@ slave = self.GetSlave(slave_pos) if slave is not None: type_infos = slave.getType() - device, alignment = self.GetModuleInfos(type_infos) + device, module_extra_params = self.GetModuleInfos(type_infos) if device is not None: infos = type_infos.copy() infos.update({"physics": device.getPhysics(), @@ -533,7 +533,7 @@ slave = self.GetSlave(slave_pos) if slave is not None: type_infos = slave.getType() - device, alignment = self.GetModuleInfos(type_infos) + device, module_extra_params = self.GetModuleInfos(type_infos) if device is not None: entries = device.GetEntriesList(limits) entries_list = entries.items() @@ -560,7 +560,7 @@ def GetSlaveVariableDataType(self, slave_pos, index, subindex): slave = self.GetSlave(slave_pos) if slave is not None: - device, alignment = self.GetModuleInfos(slave.getType()) + device, module_extra_params = self.GetModuleInfos(slave.getType()) if device is not None: entries = device.GetEntriesList() entry_infos = entries.get((index, subindex)) @@ -577,7 +577,7 @@ type_infos = slave.getType() if vendor is not None and ExtractHexDecValue(type_infos["vendor"]) != vendor: continue - device, alignment = self.GetModuleInfos(type_infos) + device, module_extra_params = self.GetModuleInfos(type_infos) if slave_profile is not None and slave_profile not in device.GetProfileNumbers(): continue entries.extend(self.GetSlaveVariables(slave_position, limits, device)) @@ -598,7 +598,7 @@ if slave is not None: type_infos = slave.getType() - device, alignment = self.GetModuleInfos(type_infos) + device, module_extra_params = self.GetModuleInfos(type_infos) if device is not None: sync_managers = [] for sync_manager in device.getSm(): diff -r ca1c34ff6c10 -r 6963460bfe0f etherlab/etherlab.py --- a/etherlab/etherlab.py Fri Apr 26 13:59:43 2013 +0200 +++ b/etherlab/etherlab.py Tue Apr 30 01:31:47 2013 +0200 @@ -232,9 +232,31 @@ "Access": access, "PDOMapping": pdomapping} -DEFAULT_ALIGNMENT = 8 - class ModulesLibrary: + + MODULES_EXTRA_PARAMS = [ + ("pdo_alignment", { + "column_label": _("PDO alignment"), + "column_size": 150, + "default": 8, + "description": _( +"Minimal size in bits between 2 pdo entries")}), + ("max_pdo_size", { + "column_label": _("Max entries by PDO"), + "column_size": 150, + "default": 255, + "description": _( +"""Maximal number of entries mapped in a PDO +including empty entries used for PDO alignment""")}), + ("add_pdo", { + "column_label": _("Creating new PDO"), + "column_size": 150, + "default": 0, + "description": _( +"""Adding a PDO not defined in default configuration +for mapping needed location variables +(1 if possible)""")}) + ] def __init__(self, path, parent_library=None): self.Path = path @@ -246,13 +268,13 @@ self.LoadModules() else: self.Library = None - self.LoadAlignments() + self.LoadModulesExtraParams() def GetPath(self): return self.Path - def GetAlignmentFilePath(self): - return os.path.join(self.Path, "alignments.cfg") + def GetModulesExtraParamsFilePath(self): + return os.path.join(self.Path, "modules_extra_params.cfg") def LoadModules(self): self.Library = {} @@ -310,14 +332,14 @@ if profile_filter is None or profile_filter in device.GetProfileNumbers(): product_code = device.getType().getProductCode() revision_number = device.getType().getRevisionNo() - alignment = self.GetAlignment(vendor_id, product_code, revision_number) + module_infos = {"device_type": device_type, + "vendor": vendor_id, + "product_code": product_code, + "revision_number": revision_number} + module_infos.update(self.GetModuleExtraParams(vendor_id, product_code, revision_number)) device_infos = {"name": ExtractName(device.getName()), "type": ETHERCAT_DEVICE, - "infos": {"device_type": device_type, - "vendor": vendor_id, - "product_code": product_code, - "revision_number": revision_number, - "alignment": alignment}, + "infos": module_infos, "children": []} group_infos["children"].append(device_infos) device_type_occurrences = device_dict.setdefault(device_type, []) @@ -353,7 +375,7 @@ revision_number = ExtractHexDecValue(device_infos.getType().getRevisionNo()) if (product_code == ExtractHexDecValue(module_infos["product_code"]) and revision_number == ExtractHexDecValue(module_infos["revision_number"])): - return device_infos, self.GetAlignment(vendor, product_code, revision_number) + return device_infos, self.GetModuleExtraParams(vendor, product_code, revision_number) return None, None def ImportModuleLibrary(self, filepath): @@ -363,10 +385,10 @@ return True return False - def LoadAlignments(self): - self.Alignments = {} - - csvfile_path = self.GetAlignmentFilePath() + def LoadModulesExtraParams(self): + self.ModulesExtraParams = {} + + csvfile_path = self.GetModulesExtraParamsFilePath() if os.path.exists(csvfile_path): csvfile = open(csvfile_path, "rb") sample = csvfile.read(1024) @@ -378,40 +400,53 @@ if has_header: has_header = False else: - try: - self.Alignments[tuple(map(int, row[:3]))] = int(row[3]) - except: - pass + params_values = {} + for (param, param_infos), value in zip( + self.MODULES_EXTRA_PARAMS, row[3:]): + if value != "": + params_values[param] = int(value) + self.ModulesExtraParams[ + tuple(map(int, row[:3]))] = params_values csvfile.close() - - def SaveAlignments(self): - csvfile = open(self.GetAlignmentFilePath(), "wb") + + def SaveModulesExtraParams(self): + csvfile = open(self.GetModulesExtraParamsFilePath(), "wb") + extra_params = [param for param, params_infos in self.MODULES_EXTRA_PARAMS] writer = csv.writer(csvfile, delimiter=';') - writer.writerow(['Vendor', 'product_code', 'revision_number', 'alignment']) - for (vendor, product_code, revision_number), alignment in self.Alignments.iteritems(): - writer.writerow([vendor, product_code, revision_number, alignment]) + writer.writerow(['Vendor', 'product_code', 'revision_number'] + extra_params) + for (vendor, product_code, revision_number), module_extra_params in self.ModulesExtraParams.iteritems(): + writer.writerow([vendor, product_code, revision_number] + + [module_extra_params.get(param, '') + for param in extra_params]) csvfile.close() - def SetAlignment(self, vendor, product_code, revision_number, alignment): + def SetModuleExtraParam(self, vendor, product_code, revision_number, param, value): vendor = ExtractHexDecValue(vendor) product_code = ExtractHexDecValue(product_code) revision_number = ExtractHexDecValue(revision_number) - self.Alignments[tuple([vendor, product_code, revision_number])] = alignment - self.SaveAlignments() - - def GetAlignment(self, vendor, product_code, revision_number): + module_infos = (vendor, product_code, revision_number) + self.ModulesExtraParams.setdefault(module_infos, {}) + self.ModulesExtraParams[module_infos][param] = value + + self.SaveModulesExtraParams() + + def GetModuleExtraParams(self, vendor, product_code, revision_number): vendor = ExtractHexDecValue(vendor) product_code = ExtractHexDecValue(product_code) revision_number = ExtractHexDecValue(revision_number) - alignment = self.Alignments.get(tuple([vendor, product_code, revision_number])) - if alignment is not None: - return alignment - if self.ParentLibrary is not None: - return self.ParentLibrary.GetAlignment(vendor, product_code, revision_number) - return DEFAULT_ALIGNMENT + extra_params = self.ParentLibrary.GetModuleExtraParams(vendor, product_code, revision_number) + else: + extra_params = {} + + extra_params.update(self.ModulesExtraParams.get((vendor, product_code, revision_number), {})) + + for param, param_infos in self.MODULES_EXTRA_PARAMS: + extra_params.setdefault(param, param_infos["default"]) + + return extra_params USERDATA_DIR = wx.StandardPaths.Get().GetUserDataDir() if wx.Platform != '__WXMSW__': diff -r ca1c34ff6c10 -r 6963460bfe0f etherlab/plc_cia402node.c --- a/etherlab/plc_cia402node.c Fri Apr 26 13:59:43 2013 +0200 +++ b/etherlab/plc_cia402node.c Tue Apr 30 01:31:47 2013 +0200 @@ -39,10 +39,15 @@ axis_s* axis; } __CIA402Node; -#define AXIS_UNIT_TO_USER_UNIT(param)\ -(IEC_LREAL)(param) * __CIA402Node_%(location)s.axis->RatioDenominator / __CIA402Node_%(location)s.axis->RatioNumerator -#define USER_UNIT_TO_AXIS_UNIT(param)\ -(IEC_DINT)(param * __CIA402Node_%(location)s.axis->RatioNumerator / __CIA402Node_%(location)s.axis->RatioDenominator) +#define AXIS_UNIT_TO_USER_UNIT(param, type, name)\ +(IEC_##type)(param) * __CIA402Node_%(location)s.axis->name##RatioDenominator / __CIA402Node_%(location)s.axis->name##RatioNumerator +#define USER_UNIT_TO_AXIS_UNIT(param, type, name)\ +(IEC_##type)(param * __CIA402Node_%(location)s.axis->name##RatioNumerator / __CIA402Node_%(location)s.axis->name##RatioDenominator) + +#define DEFAULT_AXIS_UNIT_TO_USER_UNIT(param) AXIS_UNIT_TO_USER_UNIT(param, LREAL,) +#define DEFAULT_USER_UNIT_TO_AXIS_UNIT(param) USER_UNIT_TO_AXIS_UNIT(param, DINT,) +#define TORQUE_AXIS_UNIT_TO_USER_UNIT(param) AXIS_UNIT_TO_USER_UNIT(param, LREAL, Torque) +#define TORQUE_USER_UNIT_TO_AXIS_UNIT(param) USER_UNIT_TO_AXIS_UNIT(param, INT, Torque) static __CIA402Node __CIA402Node_%(location)s; @@ -118,8 +123,9 @@ __CIA402Node_%(location)s.axis->CommunicationReady = *(__CIA402Node_%(location)s.StatusWord) != 0; __CIA402Node_%(location)s.axis->ReadyForPowerOn = __CIA402Node_%(location)s.state == __SwitchedOn || __OperationEnabled; __CIA402Node_%(location)s.axis->PowerFeedback = __CIA402Node_%(location)s.state == __OperationEnabled; - __CIA402Node_%(location)s.axis->ActualPosition = AXIS_UNIT_TO_USER_UNIT(*(__CIA402Node_%(location)s.ActualPosition)); - __CIA402Node_%(location)s.axis->ActualVelocity = AXIS_UNIT_TO_USER_UNIT(*(__CIA402Node_%(location)s.ActualVelocity)); + __CIA402Node_%(location)s.axis->ActualPosition = DEFAULT_AXIS_UNIT_TO_USER_UNIT(*(__CIA402Node_%(location)s.ActualPosition)); + __CIA402Node_%(location)s.axis->ActualVelocity = DEFAULT_AXIS_UNIT_TO_USER_UNIT(*(__CIA402Node_%(location)s.ActualVelocity)); + __CIA402Node_%(location)s.axis->ActualTorque = TORQUE_AXIS_UNIT_TO_USER_UNIT(*(__CIA402Node_%(location)s.ActualTorque)); // Extra variables retrieve %(extra_variables_retrieve)s @@ -152,8 +158,23 @@ break; } + // CIA402 node modes of operation computation according to axis motion mode + switch (__CIA402Node_%(location)s.axis->AxisMotionMode) { + case mc_mode_cst: + *(__CIA402Node_%(location)s.ModesOfOperation) = 0x0a; + break; + case mc_mode_csv: + *(__CIA402Node_%(location)s.ModesOfOperation) = 0x09; + break; + default: + *(__CIA402Node_%(location)s.ModesOfOperation) = 0x08; + break; + } + // Default variables publish - *(__CIA402Node_%(location)s.TargetPosition) = USER_UNIT_TO_AXIS_UNIT(__CIA402Node_%(location)s.axis->PositionSetPoint); + *(__CIA402Node_%(location)s.TargetPosition) = DEFAULT_USER_UNIT_TO_AXIS_UNIT(__CIA402Node_%(location)s.axis->PositionSetPoint); + *(__CIA402Node_%(location)s.TargetVelocity) = DEFAULT_USER_UNIT_TO_AXIS_UNIT(__CIA402Node_%(location)s.axis->VelocitySetPoint); + *(__CIA402Node_%(location)s.TargetTorque) = TORQUE_USER_UNIT_TO_AXIS_UNIT(__CIA402Node_%(location)s.axis->TorqueSetPoint); // Extra variables publish %(extra_variables_publish)s