Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
haraldwolff | 7d67cbd405 | |
haraldwolff | cfd40b86e5 | |
Harald Wolff-Thobaben | 1c2a3d6daa | |
Harald Wolff-Thobaben | 809ed925b1 | |
Harald Wolff-Thobaben | 6febe8ccd5 | |
Harald Wolff | 15b6cbe418 | |
Harald Wolff | 2dbdf5fbb9 |
|
@ -0,0 +1,13 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/modules.xml
|
||||||
|
/contentModel.xml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
/.idea.ln.ethercat.iml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -0,0 +1,154 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using ln.http.api;
|
||||||
|
|
||||||
|
namespace ln.ethercat.service
|
||||||
|
{
|
||||||
|
public delegate void RecordingWindowCompleted(EthercatProcessDataRecorder dataRecorder, EthercatProcessDataRecorder.RecordingWindow recordingWindow);
|
||||||
|
public delegate void ProcessDataRecordingStartStopDelegate(EthercatProcessDataRecorder dataRecorder);
|
||||||
|
|
||||||
|
public class EthercatProcessDataRecorder : IDisposable
|
||||||
|
{
|
||||||
|
public ECMaster ECMaster { get; }
|
||||||
|
public event RecordingWindowCompleted OnRecordingWindowCompleted;
|
||||||
|
public event ProcessDataRecordingStartStopDelegate OnStartRecording;
|
||||||
|
public event ProcessDataRecordingStartStopDelegate OnStopRecording;
|
||||||
|
|
||||||
|
public int RecordingWindowSize { get; set; } = 256;
|
||||||
|
public int RecordingWindowCount { get; set; } = 10;
|
||||||
|
|
||||||
|
|
||||||
|
PDO[] pdoMap;
|
||||||
|
public PDO[] CurrentPDOMap => pdoMap;
|
||||||
|
RecordingWindow[] recordingWindows;
|
||||||
|
int currentWindow;
|
||||||
|
|
||||||
|
public EthercatProcessDataRecorder(ECMaster ecMaster)
|
||||||
|
{
|
||||||
|
ECMaster = ecMaster;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ESMethod]
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
pdoMap = ECMaster.GetPDOMap();
|
||||||
|
SetupRamStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
OnStartRecording?.Invoke(this);
|
||||||
|
|
||||||
|
ECMaster.OnStateChange += MasterStateChanged;
|
||||||
|
ECMaster.OnProcessDataExchanged += ProcessDataExchanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ESMethod]
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (pdoMap != null)
|
||||||
|
{
|
||||||
|
ECMaster.OnProcessDataExchanged -= ProcessDataExchanged;
|
||||||
|
ECMaster.OnStateChange -= MasterStateChanged;
|
||||||
|
|
||||||
|
OnStopRecording?.Invoke(this);
|
||||||
|
|
||||||
|
pdoMap = null;
|
||||||
|
recordingWindows = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupRamStorage()
|
||||||
|
{
|
||||||
|
currentWindow = 0;
|
||||||
|
recordingWindows = new RecordingWindow[RecordingWindowCount];
|
||||||
|
for (int window=0; window < RecordingWindowCount; window++)
|
||||||
|
recordingWindows[window] = new RecordingWindow(RecordingWindowSize, pdoMap.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ProcessDataExchanged(ECMaster ecMaster)
|
||||||
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (pdoMap != null)
|
||||||
|
{
|
||||||
|
RecordingWindow recordingWindow = recordingWindows[currentWindow];
|
||||||
|
if (recordingWindow.GetNextRecordBuffer(out object[] currentRecord))
|
||||||
|
{
|
||||||
|
for (int n = 0; n < pdoMap.Length; n++)
|
||||||
|
currentRecord[n] = pdoMap[n].SDOValue.GetValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recordingWindow.Completed)
|
||||||
|
{
|
||||||
|
currentWindow++;
|
||||||
|
if (currentWindow >= recordingWindows.Length)
|
||||||
|
currentWindow = 0;
|
||||||
|
|
||||||
|
ThreadPool.QueueUserWorkItem((s)=>{
|
||||||
|
OnRecordingWindowCompleted?.Invoke(this, recordingWindow);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MasterStateChanged(ECMaster ecMaster, ECSlaveState newState)
|
||||||
|
{
|
||||||
|
if (newState != ECSlaveState.OPERATIONAL)
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RecordingWindow
|
||||||
|
{
|
||||||
|
object[][] recordedData;
|
||||||
|
int nextRecord;
|
||||||
|
|
||||||
|
public bool Completed => nextRecord >= recordedData.Length;
|
||||||
|
|
||||||
|
public RecordingWindow(int windowSize,int pdomapSize)
|
||||||
|
{
|
||||||
|
recordedData = new object[windowSize][];
|
||||||
|
for (int pos=0 ; pos < windowSize ; pos++)
|
||||||
|
{
|
||||||
|
recordedData[pos] = new object[pdomapSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
nextRecord = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object[][] GetRecords() => recordedData;
|
||||||
|
public object[] GetRecords(int record) => recordedData[record];
|
||||||
|
|
||||||
|
public bool GetNextRecordBuffer(out object[] recordBuffer)
|
||||||
|
{
|
||||||
|
if (nextRecord < recordedData.Length)
|
||||||
|
{
|
||||||
|
recordBuffer = recordedData[nextRecord++];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
recordBuffer = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,12 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
using ln.application;
|
using ln.application;
|
||||||
using ln.ethercat.controller;
|
|
||||||
using ln.ethercat.controller.drives;
|
|
||||||
using ln.ethercat.service.api.v1;
|
using ln.ethercat.service.api.v1;
|
||||||
using ln.http;
|
using ln.http;
|
||||||
|
using ln.http.api;
|
||||||
using ln.http.router;
|
using ln.http.router;
|
||||||
using ln.logging;
|
using ln.logging;
|
||||||
using ln.type;
|
using ln.type;
|
||||||
|
@ -15,7 +13,6 @@ namespace ln.ethercat.service
|
||||||
{
|
{
|
||||||
public class EthercatService
|
public class EthercatService
|
||||||
{
|
{
|
||||||
|
|
||||||
public ECMaster ECMaster { get; private set; }
|
public ECMaster ECMaster { get; private set; }
|
||||||
|
|
||||||
[StaticArgument(Option = 'i', LongOption = "interface")]
|
[StaticArgument(Option = 'i', LongOption = "interface")]
|
||||||
|
@ -37,11 +34,18 @@ namespace ln.ethercat.service
|
||||||
|
|
||||||
System.Timers.Timer timerWebsockets;
|
System.Timers.Timer timerWebsockets;
|
||||||
|
|
||||||
|
EthercatProcessDataRecorder processDataRecorder;
|
||||||
public EthercatService(string interfaceName)
|
public EthercatProcessDataRecorder ProcessDataRecorder {
|
||||||
{
|
get {
|
||||||
|
if (processDataRecorder == null)
|
||||||
|
processDataRecorder = new EthercatProcessDataRecorder(ECMaster);
|
||||||
|
return processDataRecorder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public EthercatService(){}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
if (EthercatInterfaceName == null)
|
if (EthercatInterfaceName == null)
|
||||||
|
@ -92,6 +96,7 @@ namespace ln.ethercat.service
|
||||||
try{
|
try{
|
||||||
EthercatWebSocket.SendProcessData(ECMaster);
|
EthercatWebSocket.SendProcessData(ECMaster);
|
||||||
ControllerWebSocket.SendUpdates(ECMaster.Controller);
|
ControllerWebSocket.SendUpdates(ECMaster.Controller);
|
||||||
|
JSONEventWebSocketResponse.SendUpdates();
|
||||||
} catch (Exception ex)
|
} catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.Log(ex);
|
Logging.Log(ex);
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using ln.ethercat.controller;
|
||||||
|
using ln.ethercat.controller.drives;
|
||||||
|
using ln.ethercat.controller.remote;
|
||||||
|
using ln.json;
|
||||||
|
using ln.json.mapping;
|
||||||
|
using ln.logging;
|
||||||
|
|
||||||
|
namespace ln.ethercat.service
|
||||||
|
{
|
||||||
|
|
||||||
|
public enum GTOperationMode { NONE, INDEPENDENT, SCREW, PRESS }
|
||||||
|
|
||||||
|
public class GalaTechControllerLogic : ControllerLogic
|
||||||
|
{
|
||||||
|
public MyParameters Parameters { get; set; }
|
||||||
|
|
||||||
|
SDOValue svRelais;
|
||||||
|
SDOValue svEnable;
|
||||||
|
private SDOValue svMode0, svMode1, svMode2;
|
||||||
|
|
||||||
|
public GalaTechControllerLogic()
|
||||||
|
{
|
||||||
|
Parameters = new MyParameters();
|
||||||
|
if (File.Exists("gtcl.json"))
|
||||||
|
{
|
||||||
|
JSONValue configValue = JSONParser.ParseFile("gtcl.json");
|
||||||
|
JSONMapper.DefaultMapper.Apply(configValue as JSONObject, Parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
if (JSONMapper.DefaultMapper.Serialize(Parameters, out JSONValue configObject))
|
||||||
|
{
|
||||||
|
using (StreamWriter sw = new StreamWriter("gtcl.json"))
|
||||||
|
{
|
||||||
|
sw.Write(configObject.ToString());
|
||||||
|
sw.Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize(Controller controller)
|
||||||
|
{
|
||||||
|
if (!(
|
||||||
|
controller.ECMaster.GetSDOValue(1, 0x2012, 31, out svRelais) &&
|
||||||
|
controller.ECMaster.GetSDOValue(1, 0x2012, 32, out svEnable) &&
|
||||||
|
controller.ECMaster.GetSDOValue(2, 0x2008, 1, out svMode0) &&
|
||||||
|
controller.ECMaster.GetSDOValue(2, 0x2008, 2, out svMode1) &&
|
||||||
|
controller.ECMaster.GetSDOValue(2, 0x2008, 3, out svMode2)
|
||||||
|
))
|
||||||
|
throw new Exception("could not retrieve needed SDOValues");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Cycle(Controller controller)
|
||||||
|
{
|
||||||
|
GTOperationMode operationMode = GTOperationMode.NONE;
|
||||||
|
|
||||||
|
object mm0 = svMode0.GetValue();
|
||||||
|
Logging.Log(LogLevel.DEBUG,"MT: {0}", mm0);
|
||||||
|
|
||||||
|
sbyte m0 = svMode0.GetValue<sbyte>();
|
||||||
|
sbyte m1 = svMode1.GetValue<sbyte>();
|
||||||
|
sbyte m2 = svMode2.GetValue<sbyte>();
|
||||||
|
Logging.Log(LogLevel.DEBUG, "Mode Bytes: {0} {1} {2}", m0,m1,m2);
|
||||||
|
|
||||||
|
if ((m0 == 1) && (m1 == 0) && (m2 == 0))
|
||||||
|
operationMode = GTOperationMode.INDEPENDENT;
|
||||||
|
else if ((m0 == 0) && (m1 == 1) && (m2 == 0))
|
||||||
|
operationMode = GTOperationMode.SCREW;
|
||||||
|
else if ((m0 == 0) && (m1 == 0) && (m2 == 1))
|
||||||
|
operationMode = GTOperationMode.PRESS;
|
||||||
|
else
|
||||||
|
operationMode = GTOperationMode.NONE;
|
||||||
|
|
||||||
|
|
||||||
|
switch (controller.ControllerState)
|
||||||
|
{
|
||||||
|
case ControllerStates.FAULT:
|
||||||
|
svEnable.SetValue((byte)0x00);
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetTorque = 0;
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetSpeed = 0;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetTorque = 0;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetSpeed = 0;
|
||||||
|
break;
|
||||||
|
case ControllerStates.NOTREADY:
|
||||||
|
svEnable.SetValue((byte)0x01);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller.ControllerState == ControllerStates.OPERATIONAL)
|
||||||
|
{
|
||||||
|
svRelais.SetValue((byte)0x01);
|
||||||
|
|
||||||
|
switch (operationMode)
|
||||||
|
{
|
||||||
|
case GTOperationMode.NONE:
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetTorque = 0;
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetSpeed = 0;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetTorque = 0;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetSpeed = 0;
|
||||||
|
break;
|
||||||
|
case GTOperationMode.INDEPENDENT:
|
||||||
|
controller.ECMaster.DriveControllers[0].DriveMode = DriveMode.SPEED;
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetTorque = 0;
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetSpeed = controller.Remotes.FirstOrDefault()?.Targets[0] ?? 0.0;
|
||||||
|
controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.SPEED;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetTorque = 0;
|
||||||
|
|
||||||
|
switch (controller.Remotes.FirstOrDefault()?.FeederOperation)
|
||||||
|
{
|
||||||
|
case FeederOperation.LEFT:
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetSpeed = Parameters.FeedSpeedRatio * controller.Remotes.FirstOrDefault()?.Targets[1] ?? 0.0;
|
||||||
|
break;
|
||||||
|
case FeederOperation.RIGHT:
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetSpeed = Parameters.FeedSpeedRatio * -controller.Remotes.FirstOrDefault()?.Targets[1] ?? 0.0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetSpeed = 0.0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case GTOperationMode.SCREW:
|
||||||
|
controller.ECMaster.DriveControllers[0].DriveMode = DriveMode.SPEED;
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetTorque = 0;
|
||||||
|
controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.SPEED;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetTorque = 0;
|
||||||
|
|
||||||
|
switch (controller.Remotes.FirstOrDefault()?.FeederOperation)
|
||||||
|
{
|
||||||
|
case FeederOperation.LEFT:
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetSpeed = controller.Remotes.FirstOrDefault()?.Targets[0] ?? 0.0;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetSpeed = Parameters.FeedScrewGearRatio * controller.Remotes.FirstOrDefault()?.Targets[0] ?? 0.0;
|
||||||
|
break;
|
||||||
|
case FeederOperation.RIGHT:
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetSpeed = -controller.Remotes.FirstOrDefault()?.Targets[0] ?? 0.0;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetSpeed = -Parameters.FeedScrewGearRatio * controller.Remotes.FirstOrDefault()?.Targets[0] ?? 0.0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetSpeed = 0.0;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetSpeed = 0.0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case GTOperationMode.PRESS:
|
||||||
|
controller.ECMaster.DriveControllers[0].DriveMode = DriveMode.SPEED;
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetTorque = 0;
|
||||||
|
controller.ECMaster.DriveControllers[0].TargetSpeed = controller.Remotes.FirstOrDefault()?.Targets[0] ?? 0.0;
|
||||||
|
controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.TORQUE;
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetSpeed = 0;
|
||||||
|
|
||||||
|
switch (controller.Remotes.FirstOrDefault()?.FeederOperation)
|
||||||
|
{
|
||||||
|
case FeederOperation.LEFT:
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetTorque = Parameters.FeedTorqueRatio * controller.Remotes.FirstOrDefault()?.Targets[1] ?? 0.0;
|
||||||
|
break;
|
||||||
|
case FeederOperation.RIGHT:
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetTorque = -Parameters.FeedTorqueRatio * controller.Remotes.FirstOrDefault()?.Targets[1] ?? 0.0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
controller.ECMaster.DriveControllers[1].TargetTorque = 0.0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
svRelais.SetValue((byte)0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class MyParameters
|
||||||
|
{
|
||||||
|
public double FeedSpeedRatio = -1.0;
|
||||||
|
public double FeedTorqueRatio = 0.5;
|
||||||
|
public double FeedScrewGearRatio = -0.015;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,19 +8,15 @@ using ln.json.mapping;
|
||||||
namespace ln.ethercat.service
|
namespace ln.ethercat.service
|
||||||
{
|
{
|
||||||
|
|
||||||
public class MainAxFeederControllerLogic
|
public class CLGalaTechBohrautomat : ControllerLogic
|
||||||
{
|
{
|
||||||
public MyParameters Parameters { get; set; }
|
public MyParameters Parameters { get; set; }
|
||||||
|
|
||||||
ECMaster ECMaster;
|
|
||||||
|
|
||||||
SDOValue svRelais;
|
SDOValue svRelais;
|
||||||
SDOValue svEnable;
|
SDOValue svEnable;
|
||||||
|
|
||||||
public MainAxFeederControllerLogic(ECMaster ecMaster)
|
public CLGalaTechBohrautomat()
|
||||||
{
|
{
|
||||||
ECMaster = ecMaster;
|
|
||||||
|
|
||||||
Parameters = new MyParameters();
|
Parameters = new MyParameters();
|
||||||
if (File.Exists("mafcl.json"))
|
if (File.Exists("mafcl.json"))
|
||||||
{
|
{
|
||||||
|
@ -41,22 +37,38 @@ namespace ln.ethercat.service
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public override void Initialize(Controller controller)
|
||||||
{
|
{
|
||||||
if (!(
|
if (!(
|
||||||
ECMaster.GetSDOValue(1, 0x2012, 31, out svRelais) &&
|
controller.ECMaster.GetSDOValue(1, 0x2012, 31, out svRelais) &&
|
||||||
ECMaster.GetSDOValue(1, 0x2012, 32, out svEnable)
|
controller.ECMaster.GetSDOValue(1, 0x2012, 32, out svEnable)
|
||||||
))
|
))
|
||||||
throw new Exception("could not retrieve needed SDOValues");
|
throw new Exception("could not retrieve needed SDOValues");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ControllerLogic(Controller contreller)
|
public override void Cycle(Controller controller)
|
||||||
{
|
{
|
||||||
|
switch (controller.ControllerState)
|
||||||
|
{
|
||||||
|
case ControllerStates.FAULT:
|
||||||
|
svEnable.SetValue((byte)0x00);
|
||||||
|
break;
|
||||||
|
case ControllerStates.NOTREADY:
|
||||||
|
svEnable.SetValue((byte)0x01);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller.ControllerState == ControllerStates.OPERATIONAL)
|
||||||
|
{
|
||||||
|
svRelais.SetValue((byte)0x01);
|
||||||
|
} else {
|
||||||
|
svRelais.SetValue((byte)0x00);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class MyParameters {
|
public class MyParameters {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,7 @@
|
||||||
using System;
|
using System.Text;
|
||||||
using System.Data;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using ln.application;
|
using ln.application;
|
||||||
using ln.ethercat.controller;
|
|
||||||
using ln.ethercat.controller.drives;
|
|
||||||
using ln.ethercat.controller.remote;
|
using ln.ethercat.controller.remote;
|
||||||
using ln.logging;
|
using ln.logging;
|
||||||
using ln.type;
|
|
||||||
|
|
||||||
namespace ln.ethercat.service
|
namespace ln.ethercat.service
|
||||||
{
|
{
|
||||||
|
@ -25,7 +19,7 @@ namespace ln.ethercat.service
|
||||||
|
|
||||||
Logging.Log(LogLevel.INFO, "ECMBind version: {0}", versionString.ToString());
|
Logging.Log(LogLevel.INFO, "ECMBind version: {0}", versionString.ToString());
|
||||||
|
|
||||||
EthercatService ethercatService = new EthercatService(args[0]);
|
EthercatService ethercatService = new EthercatService();
|
||||||
|
|
||||||
ArgumentContainer argumentContainer = new ArgumentContainer();
|
ArgumentContainer argumentContainer = new ArgumentContainer();
|
||||||
argumentContainer.AddStaticOptions<Program>();
|
argumentContainer.AddStaticOptions<Program>();
|
||||||
|
@ -34,7 +28,7 @@ namespace ln.ethercat.service
|
||||||
|
|
||||||
ethercatService.Initialize();
|
ethercatService.Initialize();
|
||||||
ethercatService.ECMaster.OnStateChange += (ECMaster ECMaster, ECSlaveState newState) => {
|
ethercatService.ECMaster.OnStateChange += (ECMaster ECMaster, ECSlaveState newState) => {
|
||||||
if (newState == ECSlaveState.OPERATIONAL)
|
if (newState == ECSlaveState.SAFE_OP)
|
||||||
{
|
{
|
||||||
if (ECMaster.GetSDOValue(1, 0x2012, 32, out SDOValue svEnableDrives))
|
if (ECMaster.GetSDOValue(1, 0x2012, 32, out SDOValue svEnableDrives))
|
||||||
{
|
{
|
||||||
|
@ -45,28 +39,24 @@ namespace ln.ethercat.service
|
||||||
{
|
{
|
||||||
ECMaster.RequestPDOMapping(1, 0x2012, 31, true);
|
ECMaster.RequestPDOMapping(1, 0x2012, 31, true);
|
||||||
ECMaster.RequestPDOMapping(1, 0x2012, 32, true);
|
ECMaster.RequestPDOMapping(1, 0x2012, 32, true);
|
||||||
|
ECMaster.RequestPDOMapping(2, 0x2008, 1, false);
|
||||||
|
ECMaster.RequestPDOMapping(2, 0x2008, 2, false);
|
||||||
|
ECMaster.RequestPDOMapping(2, 0x2008, 3, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ethercatService.ECMaster.Controller.OnStateChanged += (controller, state) => {
|
//ethercatService.ECMaster.Controller.Add(new CLGalaTechBohrautomat());
|
||||||
Logging.Log(LogLevel.DEBUG, "ControllerState=={0}", state);
|
ethercatService.ECMaster.Controller.Add(new GalaTechControllerLogic());
|
||||||
if (state == ControllerStates.NOTREADY)
|
|
||||||
{
|
|
||||||
if (controller.ECMaster.GetSDOValue(1, 0x2012, 32, out SDOValue svEnableDrives))
|
|
||||||
{
|
|
||||||
Logging.Log(LogLevel.DEBUG, "ControllerState=={0} powering up enable signals", state);
|
|
||||||
svEnableDrives.SetValue((byte)0x01);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ethercatService.Start();
|
ethercatService.Start();
|
||||||
|
|
||||||
|
|
||||||
if (SerialRemotePort != null)
|
if (SerialRemotePort != null)
|
||||||
{
|
{
|
||||||
StupidSerialRemote stupidSerialRemote = new StupidSerialRemote(ethercatService.ECMaster.Controller, SerialRemotePort);
|
// StupidSerialRemote stupidSerialRemote = new StupidSerialRemote(ethercatService.ECMaster.Controller, SerialRemotePort);
|
||||||
stupidSerialRemote.Start();
|
// stupidSerialRemote.Start();
|
||||||
|
NewSerialRemote serialRemote =
|
||||||
|
new NewSerialRemote(ethercatService.ECMaster.Controller, SerialRemotePort);
|
||||||
|
serialRemote.Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Net.Mail;
|
using System.Net.Mail;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
@ -28,7 +29,15 @@ namespace ln.ethercat.service.api.v1
|
||||||
|
|
||||||
|
|
||||||
[GET("/sockets/controller")]
|
[GET("/sockets/controller")]
|
||||||
public HttpResponse GetControllerSocket() => new ControllerWebSocket(Controller);
|
public HttpResponse GetControllerSocket(){
|
||||||
|
JSONEventWebSocketResponse webSocket = new JSONEventWebSocketResponse(Controller);
|
||||||
|
for (int drive = 0; drive < Controller.ECMaster.DriveControllers.Length; drive++)
|
||||||
|
{
|
||||||
|
DriveController driveController = Controller.ECMaster.DriveControllers[drive];
|
||||||
|
webSocket.AddTarget(String.Format("drives/{0}", drive), driveController, false);
|
||||||
|
}
|
||||||
|
return webSocket;
|
||||||
|
}
|
||||||
|
|
||||||
// [GET("/sockets/controller/drives/:drive")]
|
// [GET("/sockets/controller/drives/:drive")]
|
||||||
// public HttpResponse GetDriveControllerSocket(int drive)
|
// public HttpResponse GetDriveControllerSocket(int drive)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using ln.ethercat.controller;
|
using ln.ethercat.controller;
|
||||||
|
@ -27,7 +26,6 @@ namespace ln.ethercat.service.api.v1
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
JSONArray jsonDriveControllers = new JSONArray();
|
JSONArray jsonDriveControllers = new JSONArray();
|
||||||
|
|
||||||
foreach (DriveController driveController in controller.ECMaster.DriveControllers)
|
foreach (DriveController driveController in controller.ECMaster.DriveControllers)
|
||||||
|
|
|
@ -88,6 +88,12 @@ namespace ln.ethercat.service.api.v1
|
||||||
|
|
||||||
[GET("/socket")]
|
[GET("/socket")]
|
||||||
HttpResponse OpenWebSocket(HttpRequest httpRequest) => new EthercatWebSocket(EthercatService);
|
HttpResponse OpenWebSocket(HttpRequest httpRequest) => new EthercatWebSocket(EthercatService);
|
||||||
|
|
||||||
|
[GET("")]
|
||||||
|
HttpResponse OpenRecorderSocket(HttpRequest httpRequest) => new RecorderWebSocket(EthercatService.ProcessDataRecorder);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,10 +2,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using ln.http.websocket;
|
using ln.http.websocket;
|
||||||
using ln.json;
|
using ln.json;
|
||||||
using ln.json.mapping;
|
using ln.json.mapping;
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
using System.Net.Http;
|
||||||
|
using ln.http.api;
|
||||||
|
using ln.http.websocket;
|
||||||
|
using ln.json;
|
||||||
|
using ln.json.mapping;
|
||||||
|
|
||||||
|
namespace ln.ethercat.service.api.v1
|
||||||
|
{
|
||||||
|
public class RecorderWebSocket : JSONEventWebSocketResponse
|
||||||
|
{
|
||||||
|
EthercatProcessDataRecorder DataRecorder;
|
||||||
|
|
||||||
|
public RecorderWebSocket(EthercatProcessDataRecorder dataRecorder)
|
||||||
|
{
|
||||||
|
OnWebSocketStateChanged += (s,state)=>{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case WebSocketState.OPEN:
|
||||||
|
dataRecorder.OnRecordingWindowCompleted += RecordingWindowCompleted;
|
||||||
|
dataRecorder.OnStartRecording += RecordingStarted;
|
||||||
|
dataRecorder.OnStopRecording += RecordingStopped;
|
||||||
|
break;
|
||||||
|
case WebSocketState.CLOSED:
|
||||||
|
dataRecorder.OnStartRecording -= RecordingStarted;
|
||||||
|
dataRecorder.OnStopRecording -= RecordingStopped;
|
||||||
|
dataRecorder.OnRecordingWindowCompleted -= RecordingWindowCompleted;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RecordingStarted(EthercatProcessDataRecorder recorder)
|
||||||
|
{
|
||||||
|
JSONObject jsonMessage = new JSONObject();
|
||||||
|
jsonMessage.Add("event","start");
|
||||||
|
if (JSONMapper.DefaultMapper.Serialize(recorder.CurrentPDOMap, out JSONValue jsonValue))
|
||||||
|
jsonMessage.Add("value", jsonValue);
|
||||||
|
|
||||||
|
Send(jsonMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordingStopped(EthercatProcessDataRecorder recorder)
|
||||||
|
{
|
||||||
|
JSONObject jsonMessage = new JSONObject();
|
||||||
|
jsonMessage.Add("event","stop");
|
||||||
|
jsonMessage.Add("value", JSONNull.Instance);
|
||||||
|
|
||||||
|
Send(jsonMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecordingWindowCompleted(EthercatProcessDataRecorder recorder, EthercatProcessDataRecorder.RecordingWindow recordingWindow)
|
||||||
|
{
|
||||||
|
JSONObject jsonMessage = new JSONObject();
|
||||||
|
jsonMessage.Add("event","window");
|
||||||
|
if (JSONMapper.DefaultMapper.Serialize(recordingWindow.GetRecords(), out JSONValue jsonRecords))
|
||||||
|
jsonMessage.Add("value", jsonRecords);
|
||||||
|
|
||||||
|
Send(jsonMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,16 +2,18 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<Version>0.1.0</Version>
|
<Version>0.1.2</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ln.type" Version="0.1.7-ci" />
|
<PackageReference Include="ln.type" Version="0.1.7" />
|
||||||
<PackageReference Include="ln.logging" Version="1.0.2" />
|
<PackageReference Include="ln.logging" Version="1.0.2" />
|
||||||
<PackageReference Include="ln.json" Version="1.0.6" />
|
<PackageReference Include="ln.json" Version="1.0.7" />
|
||||||
<PackageReference Include="ln.http" Version="0.4.0-ci" />
|
<PackageReference Include="ln.http" Version="0.4.1" />
|
||||||
<PackageReference Include="ln.http.api" Version="0.0.6-ci" />
|
<PackageReference Include="ln.http.api" Version="0.0.6" />
|
||||||
|
<!--ProjectReference Include="../../ln.http.api/ln.http.api/ln.http.api.csproj" /-->
|
||||||
|
|
||||||
<ProjectReference Include="../ln.ethercat/ln.ethercat.csproj" />
|
<ProjectReference Include="../ln.ethercat/ln.ethercat.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -94,11 +94,16 @@ LN
|
||||||
component: {
|
component: {
|
||||||
template: src,
|
template: src,
|
||||||
data: function(){
|
data: function(){
|
||||||
let d = { controller: {}, drive_controller: null };
|
let d = { controller: false, drive_controller: null };
|
||||||
d.socket = $ECAPP.connectWebSocket("/api/v1/sockets/controller");
|
d.socket = $ECAPP.connectWebSocket("/api/v1/sockets/controller");
|
||||||
d.socket.onmessage = (evt)=>{
|
d.socket.onmessage = (evt)=>{
|
||||||
let json = JSON.parse(evt.data);
|
let json = JSON.parse(evt.data);
|
||||||
d.controller = json.value;
|
console.log(json);
|
||||||
|
d.controller = json.value.Controller;
|
||||||
|
let drives = []
|
||||||
|
for (let n=0;n<d.controller.DriveCount;n++)
|
||||||
|
drives.push(json.value["drives/" + n]);
|
||||||
|
d.drive_controller = drives;
|
||||||
};
|
};
|
||||||
return d;
|
return d;
|
||||||
},
|
},
|
||||||
|
@ -106,8 +111,8 @@ LN
|
||||||
drive_set: function(drive, propName, propValue){
|
drive_set: function(drive, propName, propValue){
|
||||||
let jsonMessage = {
|
let jsonMessage = {
|
||||||
event: "set",
|
event: "set",
|
||||||
|
target: `drives/${drive}`,
|
||||||
value: {
|
value: {
|
||||||
drive: drive,
|
|
||||||
name: propName,
|
name: propName,
|
||||||
value: propValue
|
value: propValue
|
||||||
}
|
}
|
||||||
|
@ -117,6 +122,7 @@ LN
|
||||||
ctrl_set: function(propName, propValue){
|
ctrl_set: function(propName, propValue){
|
||||||
let jsonMessage = {
|
let jsonMessage = {
|
||||||
event: "set",
|
event: "set",
|
||||||
|
target: "Controller",
|
||||||
value: {
|
value: {
|
||||||
name: propName,
|
name: propName,
|
||||||
value: propValue
|
value: propValue
|
||||||
|
@ -128,6 +134,7 @@ LN
|
||||||
arguments = arguments || [];
|
arguments = arguments || [];
|
||||||
let jsonMessage = {
|
let jsonMessage = {
|
||||||
event: "action",
|
event: "action",
|
||||||
|
target: "Controller",
|
||||||
value: {
|
value: {
|
||||||
method: methodName,
|
method: methodName,
|
||||||
arguments: arguments
|
arguments: arguments
|
||||||
|
|
|
@ -19,17 +19,24 @@ header > .wrapper {
|
||||||
|
|
||||||
main, .flex {
|
main, .flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
flex-wrap: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
main > *, .flex > * {
|
main > *, .flex > * {
|
||||||
flex-basis: 100%;
|
flex-basis: 100%;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
margin: 0px 8px;
|
margin: 0px 8px;
|
||||||
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
main > aside, .flex > .aside{
|
main > aside, .flex > .aside{
|
||||||
flex-basis: 25%;
|
flex-basis: 25%;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
min-width: 25%;
|
min-width: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +74,25 @@ fieldset {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fieldset > * {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset > label, fieldset > .label {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: 5%;
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 12px;
|
||||||
|
padding-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
fieldset > :first-child {
|
fieldset > :first-child {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
flex-basis: 50%;
|
flex-basis: 25%;
|
||||||
}
|
}
|
||||||
fieldset > :nth-child(2) {
|
fieldset > :nth-child(2) {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
@ -80,9 +103,11 @@ fieldset > :last-child {
|
||||||
flex-basis: 25%;
|
flex-basis: 25%;
|
||||||
}
|
}
|
||||||
fieldset.equal > * {
|
fieldset.equal > * {
|
||||||
flex-basis: 50%;
|
flex-basis: 25%;
|
||||||
margin: 4px;
|
margin: 4px;
|
||||||
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -117,6 +142,7 @@ fieldset.equal > * {
|
||||||
margin: 2px 8px;
|
margin: 2px 8px;
|
||||||
border-radius: 8px;;
|
border-radius: 8px;;
|
||||||
background-color: #808080;
|
background-color: #808080;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
.state.large {
|
.state.large {
|
||||||
width: 240px;
|
width: 240px;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<div>
|
<div>
|
||||||
<h1>Controller</h1>
|
<h1>Controller</h1>
|
||||||
<div class="panel flex">
|
<div v-if="controller" class="panel flex">
|
||||||
<column>
|
<column>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label>Status</label>
|
<label>Status</label>
|
||||||
<span class="state" :class="controller.State">{{ controller.State }}</span>
|
<span class="state" :class="controller.ControllerState">{{ controller.ControllerState }}</span>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="equal">
|
<fieldset class="equal">
|
||||||
<button @click="ctrl_action('DisableDrives');">DISABLE</button>
|
<button @click="ctrl_action('DisableDrives');">DISABLE</button>
|
||||||
|
@ -18,20 +18,20 @@
|
||||||
</column>
|
</column>
|
||||||
<column>
|
<column>
|
||||||
<div class="group"
|
<div class="group"
|
||||||
v-for="drive,key in controller.Drives"
|
v-for="drive,key in drive_controller"
|
||||||
>
|
>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label>Drive {{ key }}</label>
|
<label>Drive {{ key }}</label>
|
||||||
<span class="state" :class="drive.DriveState">{{ drive.DriveState }}</span>
|
<span class="state" :class="drive.DriveState">{{ drive.DriveState }}</span>
|
||||||
<span class="state large" :class="drive.OEMState">{{ drive.OEMState }}</span>
|
<span class="state large" :class="drive.OEMState">{{ drive.OEMState }}</span>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="equal">
|
<fieldset class="">
|
||||||
<label>Drive Mode</label>
|
<label>Drive Mode</label>
|
||||||
<span class="value">{{ drive.DriveMode }}</span>
|
<span class="value">{{ drive.DriveMode }}</span>
|
||||||
<label>Velocity</label>
|
<label>Velocity</label>
|
||||||
<meter :value="Math.abs(drive.ActualSpeed)" min="0.0" max="1.5" low="0.8" high="1.0" optimum="0.7"></meter>
|
<meter :value="Math.abs(drive.ActualSpeed)" min="0.0" max="1.5" low="0.8" high="1.0" optimum="0.7"></meter>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="equal">
|
<fieldset class="">
|
||||||
<label>TargetValue</label>
|
<label>TargetValue</label>
|
||||||
<input type="range" step="0.05" min="-1.0" max="1.0" v-model="drive.TargetValue" @input="drive_set(key, 'TargetValue', drive.TargetValue);">
|
<input type="range" step="0.05" min="-1.0" max="1.0" v-model="drive.TargetValue" @input="drive_set(key, 'TargetValue', drive.TargetValue);">
|
||||||
<label>Torque</label>
|
<label>Torque</label>
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace ln.ethercat
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void ECStateChange(ECMaster sender,ECSlaveState newState);
|
public delegate void ECStateChange(ECMaster sender,ECSlaveState newState);
|
||||||
|
public delegate void ProcessDataExchanged(ECMaster ecMaster);
|
||||||
|
|
||||||
public class ECMaster
|
public class ECMaster
|
||||||
{
|
{
|
||||||
|
@ -50,6 +51,7 @@ namespace ln.ethercat
|
||||||
|
|
||||||
|
|
||||||
public event ECStateChange OnStateChange;
|
public event ECStateChange OnStateChange;
|
||||||
|
public event ProcessDataExchanged OnProcessDataExchanged;
|
||||||
|
|
||||||
public string InterfaceName { get; }
|
public string InterfaceName { get; }
|
||||||
|
|
||||||
|
@ -270,6 +272,8 @@ namespace ln.ethercat
|
||||||
ScheduleRestart();
|
ScheduleRestart();
|
||||||
stopProcessData = true;
|
stopProcessData = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
OnProcessDataExchanged?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Thread.Sleep(INTERVALL_PROCESSDATA);
|
Thread.Sleep(INTERVALL_PROCESSDATA);
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using ln.ethercat.controller.drives;
|
using ln.ethercat.controller.drives;
|
||||||
|
using ln.http.api;
|
||||||
using ln.logging;
|
using ln.logging;
|
||||||
|
|
||||||
namespace ln.ethercat.controller
|
namespace ln.ethercat.controller
|
||||||
|
@ -10,6 +11,8 @@ namespace ln.ethercat.controller
|
||||||
public delegate void ControllerLogicDelegate(Controller controller);
|
public delegate void ControllerLogicDelegate(Controller controller);
|
||||||
public delegate void ControllerStateChangeDelegate(Controller controller, ControllerStates newState);
|
public delegate void ControllerStateChangeDelegate(Controller controller, ControllerStates newState);
|
||||||
|
|
||||||
|
public delegate bool ControllerIsSafeToEnable(Controller controller);
|
||||||
|
|
||||||
public enum ControllerStates {
|
public enum ControllerStates {
|
||||||
NONE,
|
NONE,
|
||||||
NOTREADY,
|
NOTREADY,
|
||||||
|
@ -26,28 +29,46 @@ namespace ln.ethercat.controller
|
||||||
public event ControllerStateChangeDelegate OnStateChanging;
|
public event ControllerStateChangeDelegate OnStateChanging;
|
||||||
public event ControllerStateChangeDelegate OnStateChanged;
|
public event ControllerStateChangeDelegate OnStateChanged;
|
||||||
|
|
||||||
|
public event ControllerIsSafeToEnable OnIsSafeToEnable;
|
||||||
|
|
||||||
public ECMaster ECMaster { get; }
|
public ECMaster ECMaster { get; }
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public bool IgnoreRemoteInterface { get; set; }
|
public bool IgnoreRemoteInterface { get; set; }
|
||||||
|
|
||||||
|
private ISet<ControllerRemote> _remotes = new HashSet<ControllerRemote>();
|
||||||
|
public IEnumerable<ControllerRemote> Remotes => _remotes;
|
||||||
|
|
||||||
List<ControlLoop> controlLoops = new List<ControlLoop>();
|
List<ControlLoop> controlLoops = new List<ControlLoop>();
|
||||||
public ControlLoop[] ControlLoops => controlLoops.ToArray();
|
public ControlLoop[] ControlLoops => controlLoops.ToArray();
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public ControllerStates ControllerState { get; private set; }
|
public ControllerStates ControllerState { get; private set; }
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public double ControllerLoopInterval { get; set; } = 0.1;
|
public double ControllerLoopInterval { get; set; } = 0.1;
|
||||||
|
[ESProperty]
|
||||||
public double ControllerLoopFrequency {
|
public double ControllerLoopFrequency {
|
||||||
get => 1.0 / ControllerLoopInterval;
|
get => 1.0 / ControllerLoopInterval;
|
||||||
set => ControllerLoopInterval = 1.0 / value;
|
set => ControllerLoopInterval = 1.0 / value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public long CycleCounter { get; private set; }
|
public long CycleCounter { get; private set; }
|
||||||
|
|
||||||
Thread threadWatchdog;
|
Thread threadWatchdog;
|
||||||
int wdogCounter;
|
int wdogCounter;
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public bool DisableRemoteWatchdog { get; set; }
|
public bool DisableRemoteWatchdog { get; set; }
|
||||||
int remoteWatchdogCounter;
|
int remoteWatchdogCounter;
|
||||||
public int WatchdogReset { get; set; } = 5;
|
public int WatchdogReset { get; set; } = 5;
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
|
public int DriveCount => ECMaster.DriveControllers.Length;
|
||||||
|
|
||||||
|
HashSet<ControllerLogic> controllerLogics = new HashSet<ControllerLogic>();
|
||||||
|
|
||||||
public Controller(ECMaster ecMaster)
|
public Controller(ECMaster ecMaster)
|
||||||
{
|
{
|
||||||
ECMaster = ecMaster;
|
ECMaster = ecMaster;
|
||||||
|
@ -56,6 +77,12 @@ namespace ln.ethercat.controller
|
||||||
public void Add(ControlLoop controlLoop) => controlLoops.Add(controlLoop);
|
public void Add(ControlLoop controlLoop) => controlLoops.Add(controlLoop);
|
||||||
public void Remove(ControlLoop controlLoop) => controlLoops.Remove(controlLoop);
|
public void Remove(ControlLoop controlLoop) => controlLoops.Remove(controlLoop);
|
||||||
|
|
||||||
|
public void Add(ControllerLogic controllerLogic) => controllerLogics.Add(controllerLogic);
|
||||||
|
public void Remove(ControllerLogic controllerLogic) => controllerLogics.Remove(controllerLogic);
|
||||||
|
|
||||||
|
public void Add(ControllerRemote remote) => _remotes.Add(remote);
|
||||||
|
public void Remove(ControllerRemote remote) => _remotes.Remove(remote);
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
CycleCounter = 0;
|
CycleCounter = 0;
|
||||||
|
@ -68,6 +95,9 @@ namespace ln.ethercat.controller
|
||||||
|
|
||||||
foreach (DriveController driveController in ECMaster.DriveControllers)
|
foreach (DriveController driveController in ECMaster.DriveControllers)
|
||||||
driveController.Initialize();
|
driveController.Initialize();
|
||||||
|
|
||||||
|
foreach (ControllerLogic controllerLogic in controllerLogics)
|
||||||
|
controllerLogic.Initialize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateControllerState()
|
void UpdateControllerState()
|
||||||
|
@ -98,6 +128,12 @@ namespace ln.ethercat.controller
|
||||||
if (driveState < nextState)
|
if (driveState < nextState)
|
||||||
nextState = driveState;
|
nextState = driveState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((ControllerState == ControllerStates.FAULT) && (nextState == ControllerStates.OPERATIONAL))
|
||||||
|
{
|
||||||
|
DisableDrives();
|
||||||
|
nextState = ControllerStates.FAULT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ChangeState(nextState);
|
ChangeState(nextState);
|
||||||
}
|
}
|
||||||
|
@ -107,6 +143,9 @@ namespace ln.ethercat.controller
|
||||||
if (newState == ControllerState)
|
if (newState == ControllerState)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ControllerState == ControllerStates.FAULT)
|
||||||
|
return;
|
||||||
|
|
||||||
OnStateChanging?.Invoke(this, newState);
|
OnStateChanging?.Invoke(this, newState);
|
||||||
|
|
||||||
switch (newState)
|
switch (newState)
|
||||||
|
@ -129,23 +168,46 @@ namespace ln.ethercat.controller
|
||||||
OnStateChanged?.Invoke(this, newState);
|
OnStateChanged?.Invoke(this, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ESMethod]
|
||||||
public void DisableDrives()
|
public void DisableDrives()
|
||||||
{
|
{
|
||||||
ChangeState(ControllerStates.DISABLING);
|
ChangeState(ControllerStates.DISABLING);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ESMethod]
|
||||||
public void EnableDrives()
|
public void EnableDrives()
|
||||||
{
|
{
|
||||||
if (ControllerState == ControllerStates.READY)
|
if (ControllerState == ControllerStates.READY)
|
||||||
{
|
{
|
||||||
ChangeState(ControllerStates.ENABLING);
|
if (!IsSafeToEnable())
|
||||||
|
ChangeState(ControllerStates.FAULT);
|
||||||
|
else
|
||||||
|
ChangeState(ControllerStates.ENABLING);
|
||||||
} else {
|
} else {
|
||||||
Logging.Log(LogLevel.INFO, "Controller: EnableDrives(): Current ControllerState={0}. Refusing to enable drives", ControllerState.ToString());
|
Logging.Log(LogLevel.INFO, "Controller: EnableDrives(): Current ControllerState={0}. Refusing to enable drives", ControllerState.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsSafeToEnable()
|
||||||
|
{
|
||||||
|
if (!(OnIsSafeToEnable is null))
|
||||||
|
{
|
||||||
|
foreach (ControllerIsSafeToEnable ciste in OnIsSafeToEnable.GetInvocationList())
|
||||||
|
{
|
||||||
|
if (!ciste(this))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ESMethod]
|
||||||
public void ClearFaults()
|
public void ClearFaults()
|
||||||
{
|
{
|
||||||
|
if (ControllerState == ControllerStates.FAULT)
|
||||||
|
ControllerState = ControllerStates.NONE;
|
||||||
|
|
||||||
foreach (DriveController driveController in ECMaster.DriveControllers)
|
foreach (DriveController driveController in ECMaster.DriveControllers)
|
||||||
{
|
{
|
||||||
if (driveController.DriveState == DriveStates.ERROR)
|
if (driveController.DriveState == DriveStates.ERROR)
|
||||||
|
@ -206,6 +268,9 @@ namespace ln.ethercat.controller
|
||||||
foreach (ControlLoop controlLoop in controlLoops)
|
foreach (ControlLoop controlLoop in controlLoops)
|
||||||
controlLoop.Loop();
|
controlLoop.Loop();
|
||||||
|
|
||||||
|
foreach (ControllerLogic controllerLogic in controllerLogics)
|
||||||
|
controllerLogic.Cycle(this);
|
||||||
|
|
||||||
ControllerLogic?.Invoke(this);
|
ControllerLogic?.Invoke(this);
|
||||||
|
|
||||||
foreach (DriveController driveController in ECMaster.DriveControllers)
|
foreach (DriveController driveController in ECMaster.DriveControllers)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
using System.Transactions;
|
||||||
|
|
||||||
|
namespace ln.ethercat.controller
|
||||||
|
{
|
||||||
|
public abstract class ControllerLogic
|
||||||
|
{
|
||||||
|
public abstract void Initialize(Controller controller);
|
||||||
|
public abstract void Cycle(Controller contreller);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using ln.ethercat.controller.drives;
|
using ln.ethercat.controller.drives;
|
||||||
|
using ln.ethercat.controller.remote;
|
||||||
using ln.logging;
|
using ln.logging;
|
||||||
|
|
||||||
namespace ln.ethercat.controller
|
namespace ln.ethercat.controller
|
||||||
|
@ -14,7 +15,7 @@ namespace ln.ethercat.controller
|
||||||
CLEARFAULT, // Clear fault state
|
CLEARFAULT, // Clear fault state
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class ControllerRemote
|
public abstract class ControllerRemote : IDisposable
|
||||||
{
|
{
|
||||||
protected Controller Controller;
|
protected Controller Controller;
|
||||||
|
|
||||||
|
@ -34,7 +35,11 @@ namespace ln.ethercat.controller
|
||||||
public ControllerRemote(Controller controller)
|
public ControllerRemote(Controller controller)
|
||||||
{
|
{
|
||||||
Controller = controller;
|
Controller = controller;
|
||||||
|
Controller?.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract double[] Targets { get; set; }
|
||||||
|
public abstract FeederOperation FeederOperation { get; }
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
|
@ -70,6 +75,8 @@ namespace ln.ethercat.controller
|
||||||
protected abstract void Cycle();
|
protected abstract void Cycle();
|
||||||
protected abstract void Shutdown();
|
protected abstract void Shutdown();
|
||||||
|
|
||||||
|
public abstract bool IsSafeToEnable();
|
||||||
|
|
||||||
private void CycleThread()
|
private void CycleThread()
|
||||||
{
|
{
|
||||||
CycleCounter = 0;
|
CycleCounter = 0;
|
||||||
|
@ -101,5 +108,9 @@ namespace ln.ethercat.controller
|
||||||
Shutdown();
|
Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Controller?.Remove(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -250,14 +250,14 @@ namespace ln.ethercat.controller.drives
|
||||||
public override double ActualLoad => (double)(svActualCurrent?.GetValue<short>() ?? 0) / 1000.0;
|
public override double ActualLoad => (double)(svActualCurrent?.GetValue<short>() ?? 0) / 1000.0;
|
||||||
|
|
||||||
public override double TargetPosition {
|
public override double TargetPosition {
|
||||||
get => svTargetPosition.GetValue<int>();
|
get => svTargetPosition?.GetValue<int>() ?? 0;
|
||||||
set => svTargetPosition.SetValue((int)value);
|
set => svTargetPosition.SetValue((int)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double TargetSpeed {
|
public override double TargetSpeed {
|
||||||
get {
|
get {
|
||||||
if (ModeOfOperation == CIA402ModesOfOperation.CYCLIC_SYNC_VELOCITY)
|
if (ModeOfOperation == CIA402ModesOfOperation.CYCLIC_SYNC_VELOCITY)
|
||||||
return (double)svTargetSpeed.GetValue<int>() / (1000.0 * MotorMaxSpeed);
|
return (double)(svTargetSpeed?.GetValue<int>() ?? 0) / (1000.0 * MotorMaxSpeed);
|
||||||
return (double)(svVLTargetVelocity?.GetValue<short>() ?? 0) / MotorMaxSpeed;
|
return (double)(svVLTargetVelocity?.GetValue<short>() ?? 0) / MotorMaxSpeed;
|
||||||
}
|
}
|
||||||
set {
|
set {
|
||||||
|
@ -267,11 +267,11 @@ namespace ln.ethercat.controller.drives
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public override double TargetTorque {
|
public override double TargetTorque {
|
||||||
get => (double)svTargetTorque.GetValue<short>() / 1000.0;
|
get => (double)(svTargetTorque?.GetValue<short>() ?? 0) / 1000.0;
|
||||||
set => svTargetTorque.SetValue((short)(1000 * value));
|
set => svTargetTorque.SetValue((short)(1000 * value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int ErrorCode => svErrorCode.GetValue<int>();
|
public override int ErrorCode => svErrorCode?.GetValue<ushort>() ?? 0;
|
||||||
|
|
||||||
public override string ErrorText => ErrorCode.ToString();
|
public override string ErrorText => ErrorCode.ToString();
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Net.Http.Headers;
|
using ln.http.api;
|
||||||
using System.Runtime;
|
|
||||||
|
|
||||||
namespace ln.ethercat.controller.drives
|
namespace ln.ethercat.controller.drives
|
||||||
{
|
{
|
||||||
|
@ -26,8 +23,11 @@ namespace ln.ethercat.controller.drives
|
||||||
public abstract class DriveController
|
public abstract class DriveController
|
||||||
{
|
{
|
||||||
protected ECMaster ECMaster { get; }
|
protected ECMaster ECMaster { get; }
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public UInt16 Slave { get; }
|
public UInt16 Slave { get; }
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public bool IgnoredByController { get; set; }
|
public bool IgnoredByController { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,33 +44,53 @@ namespace ln.ethercat.controller.drives
|
||||||
/* called by controller after user logic */
|
/* called by controller after user logic */
|
||||||
public abstract void UpdateDrive();
|
public abstract void UpdateDrive();
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public abstract DriveStates DriveState { get; }
|
public abstract DriveStates DriveState { get; }
|
||||||
|
[ESProperty]
|
||||||
public abstract string OEMDriveState { get; }
|
public abstract string OEMDriveState { get; }
|
||||||
|
[ESProperty]
|
||||||
public abstract Int32 ErrorCode { get; }
|
public abstract Int32 ErrorCode { get; }
|
||||||
|
[ESProperty]
|
||||||
public abstract string ErrorText { get; }
|
public abstract string ErrorText { get; }
|
||||||
|
|
||||||
|
[ESMethod]
|
||||||
public abstract void ClearFault();
|
public abstract void ClearFault();
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public abstract DriveMode DriveMode { get; set; }
|
public abstract DriveMode DriveMode { get; set; }
|
||||||
|
[ESProperty]
|
||||||
public abstract string OEMDriveMode { get; }
|
public abstract string OEMDriveMode { get; }
|
||||||
|
|
||||||
|
[ESMethod]
|
||||||
public void PowerOn() => Power(true);
|
public void PowerOn() => Power(true);
|
||||||
|
[ESMethod]
|
||||||
public void PowerOff() => Power(false);
|
public void PowerOff() => Power(false);
|
||||||
|
[ESMethod]
|
||||||
public abstract void Power(bool poweron);
|
public abstract void Power(bool poweron);
|
||||||
|
|
||||||
|
[ESMethod]
|
||||||
public void EnableDrive() => Enable(true);
|
public void EnableDrive() => Enable(true);
|
||||||
|
[ESMethod]
|
||||||
public void DisableDrive() => Enable(false);
|
public void DisableDrive() => Enable(false);
|
||||||
|
[ESMethod]
|
||||||
public abstract void Enable(bool enabled);
|
public abstract void Enable(bool enabled);
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public abstract double ActualPosition { get; }
|
public abstract double ActualPosition { get; }
|
||||||
|
[ESProperty]
|
||||||
public abstract double ActualSpeed { get; }
|
public abstract double ActualSpeed { get; }
|
||||||
|
[ESProperty]
|
||||||
public abstract double ActualTorque { get; }
|
public abstract double ActualTorque { get; }
|
||||||
|
[ESProperty]
|
||||||
public abstract double TargetPosition { get; set; }
|
public abstract double TargetPosition { get; set; }
|
||||||
|
[ESProperty]
|
||||||
public abstract double TargetSpeed { get; set; }
|
public abstract double TargetSpeed { get; set; }
|
||||||
|
[ESProperty]
|
||||||
public abstract double TargetTorque { get; set; }
|
public abstract double TargetTorque { get; set; }
|
||||||
|
[ESProperty]
|
||||||
public abstract double ActualLoad { get; }
|
public abstract double ActualLoad { get; }
|
||||||
|
|
||||||
|
[ESProperty]
|
||||||
public virtual double TargetValue {
|
public virtual double TargetValue {
|
||||||
get {
|
get {
|
||||||
switch (DriveMode)
|
switch (DriveMode)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace ln.ethercat.controller.remote
|
||||||
|
{
|
||||||
|
public enum FeederOperation
|
||||||
|
{
|
||||||
|
NONE,
|
||||||
|
LEFT,
|
||||||
|
RIGHT,
|
||||||
|
TORQUE
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,236 @@
|
||||||
|
using System;
|
||||||
|
using System.IO.Ports;
|
||||||
|
using System.Threading;
|
||||||
|
using ln.ethercat.controller.drives;
|
||||||
|
|
||||||
|
namespace ln.ethercat.controller.remote
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
#define LED_ERROR 0x00
|
||||||
|
#define LED_RUN 0x01
|
||||||
|
#define LED_LOAD25 0x02
|
||||||
|
#define LED_LOAD50 0x03
|
||||||
|
#define LED_LOAD75 0x04
|
||||||
|
#define LED_LOAD100 0x05
|
||||||
|
#define LED_SERVICE 0x06
|
||||||
|
#define LED_AUX 0x07
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class NewSerialRemote : ControllerRemote
|
||||||
|
{
|
||||||
|
public string SerialPortName { get; }
|
||||||
|
|
||||||
|
private FeederOperation _feederOperation;
|
||||||
|
public override FeederOperation FeederOperation { get => _feederOperation; }
|
||||||
|
|
||||||
|
SerialPort serialPort;
|
||||||
|
|
||||||
|
bool stopReceiverThread;
|
||||||
|
Thread threadReceiver;
|
||||||
|
|
||||||
|
public double MainTarget { get; set; }
|
||||||
|
public double FeedTarget { get; set; }
|
||||||
|
|
||||||
|
public override double[] Targets
|
||||||
|
{
|
||||||
|
get => new[] {MainTarget, FeedTarget};
|
||||||
|
set => throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double FeedRatio { get; set; } = 0.5;
|
||||||
|
public double TorqueRatio { get; set; } = 1.0;
|
||||||
|
|
||||||
|
public NewSerialRemote(Controller controller)
|
||||||
|
:this(controller, SerialPort.GetPortNames()[0]){}
|
||||||
|
public NewSerialRemote(Controller controller, string serialDevice)
|
||||||
|
:base(controller)
|
||||||
|
{
|
||||||
|
SerialPortName = serialDevice;
|
||||||
|
CycleFrequency = 10.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Cycle()
|
||||||
|
{
|
||||||
|
byte cycleDisplayStep = (byte)(CycleCounter & 0x0F);
|
||||||
|
|
||||||
|
switch (Controller.ControllerState)
|
||||||
|
{
|
||||||
|
case ControllerStates.NOTREADY:
|
||||||
|
SetLEDs(((cycleDisplayStep & 0x07) < 0x04) ? StupidLEDs.ALL : StupidLEDs.NONE);
|
||||||
|
break;
|
||||||
|
case ControllerStates.FAULT:
|
||||||
|
SetLEDs(((cycleDisplayStep & 0x07) < 0x04) ? StupidLEDs.ERROR : StupidLEDs.NONE);
|
||||||
|
break;
|
||||||
|
case ControllerStates.READY:
|
||||||
|
SetLEDs((cycleDisplayStep < 0x08) ? StupidLEDs.RUN : StupidLEDs.NONE);
|
||||||
|
break;
|
||||||
|
case ControllerStates.OPERATIONAL:
|
||||||
|
StupidLEDs leds = StupidLEDs.RUN;
|
||||||
|
if (Controller.ECMaster.DriveControllers[0].ActualLoad >= 0.25)
|
||||||
|
leds |= StupidLEDs.LOAD25;
|
||||||
|
if (Controller.ECMaster.DriveControllers[0].ActualLoad >= 0.5)
|
||||||
|
leds |= StupidLEDs.LOAD50;
|
||||||
|
if (Controller.ECMaster.DriveControllers[0].ActualLoad >= 0.75)
|
||||||
|
leds |= StupidLEDs.LOAD75;
|
||||||
|
if (Controller.ECMaster.DriveControllers[0].ActualLoad >= 1)
|
||||||
|
leds |= StupidLEDs.LOAD100;
|
||||||
|
SetLEDs(leds);
|
||||||
|
|
||||||
|
//Controller.RemoteUpdateTarget(0, MainTarget);
|
||||||
|
|
||||||
|
// switch (FeederOperation)
|
||||||
|
// {
|
||||||
|
// case FeederOperation.NONE:
|
||||||
|
// Controller.RemoteUpdateTarget(1, 0);
|
||||||
|
// break;
|
||||||
|
// case FeederOperation.LEFT:
|
||||||
|
// if (Controller.ECMaster.DriveControllers[1].DriveMode == DriveMode.SPEED)
|
||||||
|
// {
|
||||||
|
// Controller.RemoteUpdateTarget(1, FeedTarget * FeedRatio);
|
||||||
|
// } else {
|
||||||
|
// Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.SPEED;
|
||||||
|
// Controller.RemoteUpdateTarget(1, 0);
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case FeederOperation.RIGHT:
|
||||||
|
// if (Controller.ECMaster.DriveControllers[1].DriveMode == DriveMode.SPEED)
|
||||||
|
// {
|
||||||
|
// Controller.RemoteUpdateTarget(1, -(FeedTarget * FeedRatio));
|
||||||
|
// } else {
|
||||||
|
// Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.SPEED;
|
||||||
|
// Controller.RemoteUpdateTarget(1, 0);
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// case FeederOperation.TORQUE:
|
||||||
|
// if (Controller.ECMaster.DriveControllers[1].DriveMode == DriveMode.TORQUE)
|
||||||
|
// {
|
||||||
|
// Controller.RemoteUpdateTarget(1, FeedTarget * TorqueRatio);
|
||||||
|
// } else {
|
||||||
|
// Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.TORQUE;
|
||||||
|
// Controller.RemoteUpdateTarget(1, 0);
|
||||||
|
// }
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
break;
|
||||||
|
case ControllerStates.ENABLING:
|
||||||
|
break;
|
||||||
|
case ControllerStates.DISABLING:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Receiver()
|
||||||
|
{
|
||||||
|
while (!stopReceiverThread)
|
||||||
|
{
|
||||||
|
string rxLine = serialPort.ReadLine();
|
||||||
|
//Logging.Log(LogLevel.DEBUGDETAIL, rxLine);
|
||||||
|
if (rxLine.Length >= 6)
|
||||||
|
{
|
||||||
|
ushort av = 0;
|
||||||
|
ushort.TryParse(rxLine.Substring(2,4), System.Globalization.NumberStyles.HexNumber, null, out av);
|
||||||
|
|
||||||
|
switch (rxLine[0])
|
||||||
|
{
|
||||||
|
case 'A':
|
||||||
|
int drive = rxLine[1] - '0';
|
||||||
|
double rel = (double)av / 65535;
|
||||||
|
switch (drive)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
FeedTarget = rel;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
MainTarget = rel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Controller.RemoteTriggerWatchdog();
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
switch (rxLine[1])
|
||||||
|
{
|
||||||
|
case 'P':
|
||||||
|
switch (av)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (Controller.ControllerState == ControllerStates.FAULT)
|
||||||
|
Controller.RemoteAction(CRActions.CLEARFAULT);
|
||||||
|
else if (Controller.ControllerState == ControllerStates.READY)
|
||||||
|
{
|
||||||
|
Controller.ECMaster.DriveControllers[0].DriveMode = DriveMode.SPEED;
|
||||||
|
Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.SPEED;
|
||||||
|
Controller.RemoteAction(CRActions.ENABLE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Controller.RemoteAction(CRActions.DISABLE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
switch (av)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
_feederOperation = FeederOperation.LEFT;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
_feederOperation = FeederOperation.RIGHT;
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
_feederOperation = FeederOperation.TORQUE;
|
||||||
|
break; }
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
switch (av)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 14:
|
||||||
|
_feederOperation = FeederOperation.NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLEDs(StupidLEDs leds)
|
||||||
|
{
|
||||||
|
serialPort.Write(string.Format("LS{0:X4}\r\n", (ushort)leds));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override void Initialize()
|
||||||
|
{
|
||||||
|
stopReceiverThread = false;
|
||||||
|
|
||||||
|
serialPort = new SerialPort(SerialPortName);
|
||||||
|
serialPort.BaudRate = 57600;
|
||||||
|
serialPort.Parity = Parity.None;
|
||||||
|
serialPort.DataBits = 8;
|
||||||
|
serialPort.StopBits = StopBits.One;
|
||||||
|
serialPort.Open();
|
||||||
|
|
||||||
|
if (!(threadReceiver?.IsAlive ?? false))
|
||||||
|
{
|
||||||
|
threadReceiver = new Thread(Receiver);
|
||||||
|
threadReceiver.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Shutdown()
|
||||||
|
{
|
||||||
|
stopReceiverThread = true;
|
||||||
|
serialPort.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsSafeToEnable()
|
||||||
|
{
|
||||||
|
return (MainTarget==0) && (FeedTarget == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ln.ethercat.controller.remote
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum StupidLEDs : int
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
ERROR = (1<<15),
|
||||||
|
RUN = (1<<1),
|
||||||
|
LOAD25 = (1<<2),
|
||||||
|
LOAD50 = (1<<3),
|
||||||
|
LOAD75 = (1<<4),
|
||||||
|
LOAD100 = (1<<15),
|
||||||
|
ALL = -1
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,32 +16,12 @@ namespace ln.ethercat.controller.remote
|
||||||
#define LED_AUX 0x07
|
#define LED_AUX 0x07
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum StupidLEDs : int
|
|
||||||
{
|
|
||||||
NONE = 0,
|
|
||||||
ERROR = (1<<15),
|
|
||||||
RUN = (1<<1),
|
|
||||||
LOAD25 = (1<<2),
|
|
||||||
LOAD50 = (1<<3),
|
|
||||||
LOAD75 = (1<<4),
|
|
||||||
LOAD100 = (1<<15),
|
|
||||||
ALL = -1
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum FeederOperation
|
|
||||||
{
|
|
||||||
NONE,
|
|
||||||
LEFT,
|
|
||||||
RIGHT,
|
|
||||||
TORQUE
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StupidSerialRemote : ControllerRemote
|
public class StupidSerialRemote : ControllerRemote
|
||||||
{
|
{
|
||||||
public string SerialPortName { get; }
|
public string SerialPortName { get; }
|
||||||
|
|
||||||
public FeederOperation FeederOperation { get; set; }
|
private FeederOperation _feederOperation;
|
||||||
|
public override FeederOperation FeederOperation { get => _feederOperation; }
|
||||||
|
|
||||||
SerialPort serialPort;
|
SerialPort serialPort;
|
||||||
|
|
||||||
|
@ -51,6 +31,9 @@ namespace ln.ethercat.controller.remote
|
||||||
public double MainTarget { get; set; }
|
public double MainTarget { get; set; }
|
||||||
public double FeedTarget { get; set; }
|
public double FeedTarget { get; set; }
|
||||||
|
|
||||||
|
public double FeedRatio { get; set; } = 0.5;
|
||||||
|
public double TorqueRatio { get; set; } = 1.0;
|
||||||
|
|
||||||
public StupidSerialRemote(Controller controller)
|
public StupidSerialRemote(Controller controller)
|
||||||
:this(controller, SerialPort.GetPortNames()[0]){}
|
:this(controller, SerialPort.GetPortNames()[0]){}
|
||||||
public StupidSerialRemote(Controller controller, string serialDevice)
|
public StupidSerialRemote(Controller controller, string serialDevice)
|
||||||
|
@ -97,7 +80,7 @@ namespace ln.ethercat.controller.remote
|
||||||
case FeederOperation.LEFT:
|
case FeederOperation.LEFT:
|
||||||
if (Controller.ECMaster.DriveControllers[1].DriveMode == DriveMode.SPEED)
|
if (Controller.ECMaster.DriveControllers[1].DriveMode == DriveMode.SPEED)
|
||||||
{
|
{
|
||||||
Controller.RemoteUpdateTarget(1, FeedTarget);
|
Controller.RemoteUpdateTarget(1, FeedTarget * FeedRatio);
|
||||||
} else {
|
} else {
|
||||||
Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.SPEED;
|
Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.SPEED;
|
||||||
Controller.RemoteUpdateTarget(1, 0);
|
Controller.RemoteUpdateTarget(1, 0);
|
||||||
|
@ -106,7 +89,7 @@ namespace ln.ethercat.controller.remote
|
||||||
case FeederOperation.RIGHT:
|
case FeederOperation.RIGHT:
|
||||||
if (Controller.ECMaster.DriveControllers[1].DriveMode == DriveMode.SPEED)
|
if (Controller.ECMaster.DriveControllers[1].DriveMode == DriveMode.SPEED)
|
||||||
{
|
{
|
||||||
Controller.RemoteUpdateTarget(1, -FeedTarget);
|
Controller.RemoteUpdateTarget(1, -(FeedTarget * FeedRatio));
|
||||||
} else {
|
} else {
|
||||||
Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.SPEED;
|
Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.SPEED;
|
||||||
Controller.RemoteUpdateTarget(1, 0);
|
Controller.RemoteUpdateTarget(1, 0);
|
||||||
|
@ -115,7 +98,7 @@ namespace ln.ethercat.controller.remote
|
||||||
case FeederOperation.TORQUE:
|
case FeederOperation.TORQUE:
|
||||||
if (Controller.ECMaster.DriveControllers[1].DriveMode == DriveMode.TORQUE)
|
if (Controller.ECMaster.DriveControllers[1].DriveMode == DriveMode.TORQUE)
|
||||||
{
|
{
|
||||||
Controller.RemoteUpdateTarget(1, FeedTarget);
|
Controller.RemoteUpdateTarget(1, FeedTarget * TorqueRatio);
|
||||||
} else {
|
} else {
|
||||||
Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.TORQUE;
|
Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.TORQUE;
|
||||||
Controller.RemoteUpdateTarget(1, 0);
|
Controller.RemoteUpdateTarget(1, 0);
|
||||||
|
@ -183,13 +166,13 @@ namespace ln.ethercat.controller.remote
|
||||||
switch (av)
|
switch (av)
|
||||||
{
|
{
|
||||||
case 3:
|
case 3:
|
||||||
FeederOperation = FeederOperation.LEFT;
|
_feederOperation = FeederOperation.LEFT;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
FeederOperation = FeederOperation.RIGHT;
|
_feederOperation = FeederOperation.RIGHT;
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
FeederOperation = FeederOperation.TORQUE;
|
_feederOperation = FeederOperation.TORQUE;
|
||||||
break; }
|
break; }
|
||||||
break;
|
break;
|
||||||
case 'U':
|
case 'U':
|
||||||
|
@ -198,7 +181,7 @@ namespace ln.ethercat.controller.remote
|
||||||
case 3:
|
case 3:
|
||||||
case 4:
|
case 4:
|
||||||
case 14:
|
case 14:
|
||||||
FeederOperation = FeederOperation.NONE;
|
_feederOperation = FeederOperation.NONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -215,6 +198,8 @@ namespace ln.ethercat.controller.remote
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override double[] Targets { get => new []{ MainTarget, FeedTarget }; set => throw new NotSupportedException(); }
|
||||||
|
|
||||||
protected override void Initialize()
|
protected override void Initialize()
|
||||||
{
|
{
|
||||||
stopReceiverThread = false;
|
stopReceiverThread = false;
|
||||||
|
@ -238,5 +223,10 @@ namespace ln.ethercat.controller.remote
|
||||||
stopReceiverThread = true;
|
stopReceiverThread = true;
|
||||||
serialPort.Close();
|
serialPort.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool IsSafeToEnable()
|
||||||
|
{
|
||||||
|
return (MainTarget==0) && (FeedTarget == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ln.ethercat.kinematics
|
||||||
|
{
|
||||||
|
public abstract class Joint
|
||||||
|
{
|
||||||
|
public Joint()
|
||||||
|
{
|
||||||
|
ForwardMatrix = Matrix4x4.Identity;
|
||||||
|
}
|
||||||
|
public Joint(Matrix4x4 forwardMatrix)
|
||||||
|
{
|
||||||
|
ForwardMatrix = forwardMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix4x4 ForwardMatrix { get; protected set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ln.ethercat.kinematics
|
||||||
|
{
|
||||||
|
public struct Position
|
||||||
|
{
|
||||||
|
public readonly Vector3 Base;
|
||||||
|
public readonly Vector3 X;
|
||||||
|
public readonly Vector3 Y;
|
||||||
|
public readonly Vector3 Z;
|
||||||
|
|
||||||
|
public Position(Vector3 b, Vector3 x, Vector3 y, Vector3 z)
|
||||||
|
{
|
||||||
|
Base = b;
|
||||||
|
X = x;
|
||||||
|
Y = y;
|
||||||
|
Z = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ln.ethercat.kinematics
|
||||||
|
{
|
||||||
|
public class RotationalJoint : Joint
|
||||||
|
{
|
||||||
|
private Vector3 axis;
|
||||||
|
private float angle;
|
||||||
|
|
||||||
|
public RotationalJoint()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 Axis
|
||||||
|
{
|
||||||
|
get => axis;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ForwardMatrix = Matrix4x4.CreateFromAxisAngle(value, angle);
|
||||||
|
axis = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Angle
|
||||||
|
{
|
||||||
|
get => angle;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ForwardMatrix = Matrix4x4.CreateFromAxisAngle(axis, value);
|
||||||
|
angle = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ln.ethercat.kinematics
|
||||||
|
{
|
||||||
|
public class TranslatingJoint : Joint
|
||||||
|
{
|
||||||
|
public TranslatingJoint() :base(Matrix4x4.Identity)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3 Translation
|
||||||
|
{
|
||||||
|
get => ForwardMatrix.Translation;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Matrix4x4 m = ForwardMatrix;
|
||||||
|
m.Translation = value;
|
||||||
|
ForwardMatrix = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Version>0.1.0-ci</Version>
|
<Version>0.1.2</Version>
|
||||||
<Authors>Harald Wolff-Thobaben</Authors>
|
<Authors>Harald Wolff-Thobaben</Authors>
|
||||||
<Company>l--n.de</Company>
|
<Company>l--n.de</Company>
|
||||||
<Description>A simple ethercat master based on SOEM (https://openethercatsociety.github.io/) </Description>
|
<Description>A simple ethercat master based on SOEM (https://openethercatsociety.github.io/) </Description>
|
||||||
|
@ -17,10 +17,12 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.IO.Ports" Version="5.0.0" />
|
<PackageReference Include="System.IO.Ports" Version="5.0.0" />
|
||||||
<PackageReference Include="ln.type" Version="0.1.7-ci" />
|
<PackageReference Include="ln.type" Version="0.1.7" />
|
||||||
<PackageReference Include="ln.logging" Version="1.0.2" />
|
<PackageReference Include="ln.logging" Version="1.0.2" />
|
||||||
<PackageReference Include="ln.json" Version="1.0.6" />
|
<PackageReference Include="ln.json" Version="1.0.7" />
|
||||||
<PackageReference Include="ln.collections" Version="0.1.3-ci" />
|
<PackageReference Include="ln.collections" Version="0.1.3" />
|
||||||
|
<PackageReference Include="ln.http.api" Version="0.0.6" />
|
||||||
|
<!--ProjectReference Include="../../ln.http.api/ln.http.api/ln.http.api.csproj" /-->
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
Loading…
Reference in New Issue