Improvements to WebUI
ln.build - build0.waldrennach.l--n.de build job pending
Details
ln.build - build0.waldrennach.l--n.de build job pending
Details
parent
9c054f3865
commit
1283d1c570
|
@ -36,8 +36,6 @@ namespace ln.ethercat.service
|
||||||
ethercatService.ECMaster.OnStateChange += (ECMaster ECMaster, ECSlaveState newState) => {
|
ethercatService.ECMaster.OnStateChange += (ECMaster ECMaster, ECSlaveState newState) => {
|
||||||
if (newState == ECSlaveState.OPERATIONAL)
|
if (newState == ECSlaveState.OPERATIONAL)
|
||||||
{
|
{
|
||||||
ECMaster.DriveControllers[1].IgnoredByController = true;
|
|
||||||
|
|
||||||
if (ECMaster.GetSDOValue(1, 0x2012, 32, out SDOValue svEnableDrives))
|
if (ECMaster.GetSDOValue(1, 0x2012, 32, out SDOValue svEnableDrives))
|
||||||
{
|
{
|
||||||
svEnableDrives.SetValue((byte)0x00);
|
svEnableDrives.SetValue((byte)0x00);
|
||||||
|
@ -52,7 +50,6 @@ namespace ln.ethercat.service
|
||||||
|
|
||||||
ethercatService.ECMaster.Controller.OnStateChanged += (controller, state) => {
|
ethercatService.ECMaster.Controller.OnStateChanged += (controller, state) => {
|
||||||
Logging.Log(LogLevel.DEBUG, "ControllerState=={0}", state);
|
Logging.Log(LogLevel.DEBUG, "ControllerState=={0}", state);
|
||||||
|
|
||||||
if (state == ControllerStates.NOTREADY)
|
if (state == ControllerStates.NOTREADY)
|
||||||
{
|
{
|
||||||
if (controller.ECMaster.GetSDOValue(1, 0x2012, 32, out SDOValue svEnableDrives))
|
if (controller.ECMaster.GetSDOValue(1, 0x2012, 32, out SDOValue svEnableDrives))
|
||||||
|
@ -60,9 +57,6 @@ namespace ln.ethercat.service
|
||||||
Logging.Log(LogLevel.DEBUG, "ControllerState=={0} powering up enable signals", state);
|
Logging.Log(LogLevel.DEBUG, "ControllerState=={0} powering up enable signals", state);
|
||||||
svEnableDrives.SetValue((byte)0x01);
|
svEnableDrives.SetValue((byte)0x01);
|
||||||
}
|
}
|
||||||
} else if (state == ControllerStates.READY)
|
|
||||||
{
|
|
||||||
controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.TORQUE;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
using ln.ethercat.controller;
|
using ln.ethercat.controller;
|
||||||
using ln.ethercat.controller.drives;
|
using ln.ethercat.controller.drives;
|
||||||
using ln.http.websocket;
|
using ln.http.websocket;
|
||||||
using ln.json;
|
using ln.json;
|
||||||
|
using ln.json.mapping;
|
||||||
using ln.logging;
|
using ln.logging;
|
||||||
|
using ln.type;
|
||||||
|
|
||||||
namespace ln.ethercat.service.api.v1
|
namespace ln.ethercat.service.api.v1
|
||||||
{
|
{
|
||||||
|
@ -48,6 +51,8 @@ namespace ln.ethercat.service.api.v1
|
||||||
.Add("State", controller.ControllerState.ToString())
|
.Add("State", controller.ControllerState.ToString())
|
||||||
.Add("Drives", jsonDriveControllers)
|
.Add("Drives", jsonDriveControllers)
|
||||||
.Add("CycleCounter", controller.CycleCounter)
|
.Add("CycleCounter", controller.CycleCounter)
|
||||||
|
.Add("DisableRemoteWatchdog", controller.DisableRemoteWatchdog)
|
||||||
|
.Add("IgnoreRemoteInterface", controller.IgnoreRemoteInterface)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -100,12 +105,40 @@ namespace ln.ethercat.service.api.v1
|
||||||
|
|
||||||
public override void Received(string textMessage)
|
public override void Received(string textMessage)
|
||||||
{
|
{
|
||||||
|
object target;
|
||||||
|
|
||||||
base.Received(textMessage);
|
base.Received(textMessage);
|
||||||
|
|
||||||
JSONValue jsonTextValue = JSONParser.Parse(textMessage);
|
JSONValue jsonTextValue = JSONParser.Parse(textMessage);
|
||||||
if (jsonTextValue is JSONObject jsonMessage)
|
if (jsonTextValue is JSONObject jsonMessage)
|
||||||
{
|
{
|
||||||
string eventName = jsonMessage["event"].ToNative().ToString();
|
string eventName = jsonMessage["event"].ToNative().ToString();
|
||||||
|
JSONObject jsonValue = jsonMessage["value"] as JSONObject;
|
||||||
|
|
||||||
|
switch (eventName)
|
||||||
|
{
|
||||||
|
case "set":
|
||||||
|
string propName = jsonValue["name"].ToNative().ToString();
|
||||||
|
object propValue = jsonValue["value"].ToNative();
|
||||||
|
target = Controller;
|
||||||
|
if (jsonValue.ContainsKey("drive"))
|
||||||
|
target = Controller.ECMaster.DriveControllers[(Int64)jsonValue["drive"].ToNative()];
|
||||||
|
|
||||||
|
PropertyInfo propertyInfo = target.GetType().GetProperty(propName);
|
||||||
|
propertyInfo.SetValue(target, Cast.To(propValue, propertyInfo.PropertyType));
|
||||||
|
break;
|
||||||
|
case "action":
|
||||||
|
string methodName = jsonValue["method"].ToNative().ToString();
|
||||||
|
JSONMapper.DefaultMapper.Deserialize(jsonValue["arguments"], out object[] arguments);
|
||||||
|
target = Controller;
|
||||||
|
if (jsonValue.ContainsKey("drive"))
|
||||||
|
target = Controller.ECMaster.DriveControllers[(Int64)jsonValue["drive"].ToNative()];
|
||||||
|
|
||||||
|
MethodInfo methodInfo = target.GetType().GetMethod(methodName);
|
||||||
|
methodInfo.Invoke(target,new object[0]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,12 +95,46 @@ LN
|
||||||
template: src,
|
template: src,
|
||||||
data: function(){
|
data: function(){
|
||||||
let d = { controller: {}, drive_controller: null };
|
let d = { controller: {}, drive_controller: null };
|
||||||
let socket = $ECAPP.connectWebSocket("/api/v1/sockets/controller");
|
d.socket = $ECAPP.connectWebSocket("/api/v1/sockets/controller");
|
||||||
socket.onmessage = (evt)=>{
|
d.socket.onmessage = (evt)=>{
|
||||||
let json = JSON.parse(evt.data);
|
let json = JSON.parse(evt.data);
|
||||||
d.controller = json;
|
d.controller = json.value;
|
||||||
};
|
};
|
||||||
return d;
|
return d;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
drive_set: function(drive, propName, propValue){
|
||||||
|
let jsonMessage = {
|
||||||
|
event: "set",
|
||||||
|
value: {
|
||||||
|
drive: drive,
|
||||||
|
name: propName,
|
||||||
|
value: propValue
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.socket.send(JSON.stringify(jsonMessage));
|
||||||
|
},
|
||||||
|
ctrl_set: function(propName, propValue){
|
||||||
|
let jsonMessage = {
|
||||||
|
event: "set",
|
||||||
|
value: {
|
||||||
|
name: propName,
|
||||||
|
value: propValue
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.socket.send(JSON.stringify(jsonMessage));
|
||||||
|
},
|
||||||
|
ctrl_action: function(methodName, arguments){
|
||||||
|
arguments = arguments || [];
|
||||||
|
let jsonMessage = {
|
||||||
|
event: "action",
|
||||||
|
value: {
|
||||||
|
method: methodName,
|
||||||
|
arguments: arguments
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.socket.send(JSON.stringify(jsonMessage));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -22,6 +22,7 @@ main, .flex {
|
||||||
}
|
}
|
||||||
|
|
||||||
main > *, .flex > * {
|
main > *, .flex > * {
|
||||||
|
flex-basis: 100%;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
margin: 0px 8px;
|
margin: 0px 8px;
|
||||||
}
|
}
|
||||||
|
@ -29,9 +30,17 @@ main > *, .flex > * {
|
||||||
main > aside, .flex > .aside{
|
main > aside, .flex > .aside{
|
||||||
flex-basis: 25%;
|
flex-basis: 25%;
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
|
min-width: 25%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.group {
|
||||||
|
display: block;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
.group > fieldset {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
border-bottom: 1px solid black;
|
border-bottom: 1px solid black;
|
||||||
|
@ -43,20 +52,41 @@ button, span {
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
button.selected {
|
||||||
|
color: #10E010;
|
||||||
|
}
|
||||||
|
button.true {
|
||||||
|
color: #10E010;
|
||||||
|
}
|
||||||
|
button.false {
|
||||||
|
color: #B0B0B0;
|
||||||
|
}
|
||||||
|
|
||||||
fieldset {
|
fieldset {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldset > label {
|
fieldset > :first-child {
|
||||||
flex-grow: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset > input, fieldset > .value {
|
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
flex-basis: 50%;
|
||||||
|
}
|
||||||
|
fieldset > :nth-child(2) {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-basis: 40%;
|
||||||
|
}
|
||||||
|
fieldset > :last-child {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-basis: 25%;
|
||||||
|
}
|
||||||
|
fieldset.equal > * {
|
||||||
|
flex-basis: 50%;
|
||||||
|
margin: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
.panel {
|
.panel {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +118,24 @@ fieldset > input, fieldset > .value {
|
||||||
border-radius: 8px;;
|
border-radius: 8px;;
|
||||||
background-color: #808080;
|
background-color: #808080;
|
||||||
}
|
}
|
||||||
|
.state.large {
|
||||||
|
width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.state.READY {
|
||||||
|
color: #108010;
|
||||||
|
}
|
||||||
|
.state.OPERATIONAL {
|
||||||
|
color: #10E010;
|
||||||
|
}
|
||||||
|
.state.ERROR, .state.FAULT {
|
||||||
|
color: white;
|
||||||
|
background-color: #C04040;
|
||||||
|
}
|
||||||
|
.state.BOOT, .state.INIT {
|
||||||
|
color: #000080;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.state.active {
|
.state.active {
|
||||||
background-color: #10E010;
|
background-color: #10E010;
|
||||||
|
@ -104,15 +152,10 @@ fieldset > input, fieldset > .value {
|
||||||
.state.active.orange {
|
.state.active.orange {
|
||||||
background-color: #e0a810;
|
background-color: #e0a810;
|
||||||
}
|
}
|
||||||
|
.state.SAFE_OP {
|
||||||
|
|
||||||
.OPERATIONAL {
|
|
||||||
background-color: #10E010;
|
|
||||||
}
|
|
||||||
.SAFE_OP {
|
|
||||||
background-color: #e0a810;
|
background-color: #e0a810;
|
||||||
}
|
}
|
||||||
.PRE_OP {
|
.state.PRE_OP {
|
||||||
background-color: #B0B0B0;
|
background-color: #B0B0B0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,47 @@
|
||||||
<div>
|
<div>
|
||||||
<h1>Controller</h1>
|
<h1>Controller</h1>
|
||||||
|
<div class="panel flex">
|
||||||
|
<column>
|
||||||
|
<fieldset>
|
||||||
|
<label>Status</label>
|
||||||
|
<span class="state" :class="controller.State">{{ controller.State }}</span>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="equal">
|
||||||
|
<button @click="ctrl_action('DisableDrives');">DISABLE</button>
|
||||||
|
<button @click="ctrl_action('EnableDrives');">ENABLE</button>
|
||||||
|
<button @click="ctrl_action('ClearFaults');">CLEAR FAULT</button>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="equal">
|
||||||
|
<button @click="ctrl_set('DisableRemoteWatchdog', !controller.DisableRemoteWatchdog);" :class="controller.DisableRemoteWatchdog.toString()">DisableRemoteWatchdog</button>
|
||||||
|
<button @click="ctrl_set('IgnoreRemoteInterface', !controller.IgnoreRemoteInterface);" :class="controller.IgnoreRemoteInterface.toString()">IgnoreRemoteInterface</button>
|
||||||
|
</fieldset>
|
||||||
|
</column>
|
||||||
|
<column>
|
||||||
|
<div class="group"
|
||||||
|
v-for="drive,key in controller.Drives"
|
||||||
|
>
|
||||||
|
<fieldset>
|
||||||
|
<label>Drive {{ key }}</label>
|
||||||
|
<span class="state" :class="drive.DriveState">{{ drive.DriveState }}</span>
|
||||||
|
<span class="state large" :class="drive.OEMState">{{ drive.OEMState }}</span>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="equal">
|
||||||
|
<label>Drive Mode</label>
|
||||||
|
<span class="value">{{ drive.DriveMode }}</span>
|
||||||
|
<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>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="equal">
|
||||||
|
<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);">
|
||||||
|
<label>Torque</label>
|
||||||
|
<meter :value="Math.abs(drive.ActualTorque)" min="0.0" max="1.5" low="0.8" high="1.0" optimum="0.7"></meter>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</column>
|
||||||
|
</div>
|
||||||
<p>
|
<p>
|
||||||
{{ controller }}
|
{{ controller }}
|
||||||
</p>
|
</p>
|
||||||
<div v-if="drive_controller">
|
|
||||||
<h2>Drive Controller</h2>
|
|
||||||
<button @click="drive_poweroff">Power Off</button>
|
|
||||||
<button @click="drive_poweron" >Power On</button>
|
|
||||||
<button @click="drive_disable" >Disable</button>
|
|
||||||
<button @click="drive_enable">Enable</button>
|
|
||||||
<button @click="drive_clearfault">Clear Fault</button>
|
|
||||||
|
|
||||||
<button @click="drive_drivemode('Position')">Mode: POS</button>
|
|
||||||
<button @click="drive_drivemode('Speed')">Mode: SPEED</button>
|
|
||||||
<button @click="drive_drivemode('Torque')">Mode: TORQUE</button>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
{{ drive_controller }}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<fieldset>
|
|
||||||
<label>Target Torque:</label>
|
|
||||||
<input type="range" min="-1000" max="1000" v-model="targetTorque" id="targetTorque" @input="setProperty('TargetValue', targetTorque);">
|
|
||||||
<input type="number" v-model="targetTorque" @change="setProperty('TargetValue', targetTorque);">
|
|
||||||
<button @click="targetTorque = 0; setProperty('TargetValue', targetTorque);">ZERO</button>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
|
@ -7,7 +7,6 @@ using ln.logging;
|
||||||
|
|
||||||
namespace ln.ethercat.controller
|
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);
|
||||||
|
|
||||||
|
@ -45,6 +44,8 @@ namespace ln.ethercat.controller
|
||||||
|
|
||||||
Thread threadWatchdog;
|
Thread threadWatchdog;
|
||||||
int wdogCounter;
|
int wdogCounter;
|
||||||
|
public bool DisableRemoteWatchdog { get; set; }
|
||||||
|
int remoteWatchdogCounter;
|
||||||
public int WatchdogReset { get; set; } = 5;
|
public int WatchdogReset { get; set; } = 5;
|
||||||
|
|
||||||
public Controller(ECMaster ecMaster)
|
public Controller(ECMaster ecMaster)
|
||||||
|
@ -67,7 +68,6 @@ namespace ln.ethercat.controller
|
||||||
|
|
||||||
foreach (DriveController driveController in ECMaster.DriveControllers)
|
foreach (DriveController driveController in ECMaster.DriveControllers)
|
||||||
driveController.Initialize();
|
driveController.Initialize();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateControllerState()
|
void UpdateControllerState()
|
||||||
|
@ -172,15 +172,17 @@ namespace ln.ethercat.controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RemoteTriggerWatchdog() => remoteWatchdogCounter = 5;
|
||||||
|
|
||||||
public void RemoteUpdateTarget(int drive, double targetValue)
|
public void RemoteUpdateTarget(int drive, double targetValue)
|
||||||
{
|
{
|
||||||
if (!IgnoreRemoteInterface)
|
if (!IgnoreRemoteInterface)
|
||||||
{
|
{
|
||||||
targetValue = Math.Clamp(targetValue, 0, 1);
|
targetValue = Math.Clamp(targetValue, -1, 1);
|
||||||
|
|
||||||
if (drive < 0)
|
if (drive < 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(targetValue));
|
throw new ArgumentOutOfRangeException(nameof(targetValue));
|
||||||
if (drive > ECMaster.DriveControllers.Length)
|
if (drive >= ECMaster.DriveControllers.Length)
|
||||||
{
|
{
|
||||||
Logging.Log(LogLevel.WARNING, "Controller: RemoteUpdateTarget(): trying to update non-existent drive {0}", drive);
|
Logging.Log(LogLevel.WARNING, "Controller: RemoteUpdateTarget(): trying to update non-existent drive {0}", drive);
|
||||||
return;
|
return;
|
||||||
|
@ -217,7 +219,19 @@ namespace ln.ethercat.controller
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Thread.Sleep(TimeSpan.FromSeconds(ControllerLoopInterval));
|
Thread.Sleep(TimeSpan.FromSeconds(ControllerLoopInterval));
|
||||||
if ((wdogCounter--) < 0)
|
|
||||||
|
if (wdogCounter > 0)
|
||||||
|
{
|
||||||
|
wdogCounter--;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
ChangeState(ControllerStates.FAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remoteWatchdogCounter > 0)
|
||||||
|
{
|
||||||
|
remoteWatchdogCounter--;
|
||||||
|
} else if (!DisableRemoteWatchdog)
|
||||||
{
|
{
|
||||||
ChangeState(ControllerStates.FAULT);
|
ChangeState(ControllerStates.FAULT);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using ln.logging;
|
using ln.logging;
|
||||||
|
|
||||||
namespace ln.ethercat.controller.drives
|
namespace ln.ethercat.controller.drives
|
||||||
|
@ -42,6 +43,8 @@ namespace ln.ethercat.controller.drives
|
||||||
SDOValue svModesOfOperation;
|
SDOValue svModesOfOperation;
|
||||||
SDOValue svModesOfOperationDisplay;
|
SDOValue svModesOfOperationDisplay;
|
||||||
SDOValue svActualCurrent;
|
SDOValue svActualCurrent;
|
||||||
|
SDOValue svVLTargetVelocity;
|
||||||
|
SDOValue svVLActualVelocity;
|
||||||
|
|
||||||
SDOValue svMaxSpeed;
|
SDOValue svMaxSpeed;
|
||||||
|
|
||||||
|
@ -62,7 +65,9 @@ namespace ln.ethercat.controller.drives
|
||||||
new PDOMappingRequest(slave, 0x6077, 0, false),
|
new PDOMappingRequest(slave, 0x6077, 0, false),
|
||||||
new PDOMappingRequest(slave, 0x6060, 0, true),
|
new PDOMappingRequest(slave, 0x6060, 0, true),
|
||||||
new PDOMappingRequest(slave, 0x6061, 0, false),
|
new PDOMappingRequest(slave, 0x6061, 0, false),
|
||||||
new PDOMappingRequest(slave, 0x6078, 0, false)
|
new PDOMappingRequest(slave, 0x6078, 0, false),
|
||||||
|
new PDOMappingRequest(slave, 0x6042, 0, true),
|
||||||
|
new PDOMappingRequest(slave, 0x6044, 0, false),
|
||||||
};
|
};
|
||||||
ecMaster.RequestPDOMapping(mappingRequests);
|
ecMaster.RequestPDOMapping(mappingRequests);
|
||||||
}
|
}
|
||||||
|
@ -82,68 +87,81 @@ namespace ln.ethercat.controller.drives
|
||||||
ECMaster.GetSDOValue(Slave, 0x6060, 0, out svModesOfOperation) &&
|
ECMaster.GetSDOValue(Slave, 0x6060, 0, out svModesOfOperation) &&
|
||||||
ECMaster.GetSDOValue(Slave, 0x6061, 0, out svModesOfOperationDisplay) &&
|
ECMaster.GetSDOValue(Slave, 0x6061, 0, out svModesOfOperationDisplay) &&
|
||||||
ECMaster.GetSDOValue(Slave, 0x6080, 0, out svMaxSpeed) &&
|
ECMaster.GetSDOValue(Slave, 0x6080, 0, out svMaxSpeed) &&
|
||||||
|
ECMaster.GetSDOValue(Slave, 0x6044, 0, out svVLActualVelocity) &&
|
||||||
|
ECMaster.GetSDOValue(Slave, 0x6042, 0, out svVLTargetVelocity) &&
|
||||||
ECMaster.GetSDOValue(Slave, 0x6078, 0, out svActualCurrent)
|
ECMaster.GetSDOValue(Slave, 0x6078, 0, out svActualCurrent)
|
||||||
))
|
))
|
||||||
throw new ArgumentOutOfRangeException("CIA402Controller could not retrieve SDOvalues for CiA402 profile");
|
throw new ArgumentOutOfRangeException("CIA402Controller could not retrieve SDOvalues for CiA402 profile");
|
||||||
|
|
||||||
|
MotorMaxSpeed = svMaxSpeed.GetValue<UInt32>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void UpdateStates() {
|
public override void UpdateStates() {
|
||||||
CIA402State = GetCIA402State();
|
CIA402State = GetCIA402State();
|
||||||
}
|
}
|
||||||
public override void UpdateDrive() {
|
public override void UpdateDrive()
|
||||||
|
{
|
||||||
if (CIA402State != CIA402TargetState)
|
if (CIA402TargetState != CIA402States.UNDEFINED)
|
||||||
{
|
{
|
||||||
switch (CIA402State)
|
if (CIA402State != CIA402TargetState)
|
||||||
{
|
{
|
||||||
case CIA402States.NOT_READY_TO_SWITCH_ON:
|
switch (CIA402State)
|
||||||
svControlWord.SetValue((ushort)0x0000);
|
{
|
||||||
ModeOfOperation = CIA402ModesOfOperation.CYCLIC_SYNC_TORQUE;
|
case CIA402States.FAULT:
|
||||||
break;
|
case CIA402States.FAULT_REACTION_ACTIVE:
|
||||||
case CIA402States.SWITCH_ON_DISABLED:
|
CIA402TargetState = CIA402States.UNDEFINED;
|
||||||
svControlWord.SetValue((ushort)0x0006);
|
break;
|
||||||
break;
|
case CIA402States.NOT_READY_TO_SWITCH_ON:
|
||||||
case CIA402States.READY_TO_SWITCH_ON:
|
svControlWord.SetValue((ushort)0x0000);
|
||||||
switch (CIA402TargetState)
|
ModeOfOperation = CIA402ModesOfOperation.CYCLIC_SYNC_TORQUE;
|
||||||
{
|
break;
|
||||||
case CIA402States.SWITCH_ON_DISABLED:
|
case CIA402States.SWITCH_ON_DISABLED:
|
||||||
svControlWord.SetValue((ushort)0x0000);
|
svControlWord.SetValue((ushort)0x0006);
|
||||||
break;
|
break;
|
||||||
case CIA402States.SWITCHED_ON:
|
case CIA402States.READY_TO_SWITCH_ON:
|
||||||
case CIA402States.OPERATION_ENABLED:
|
switch (CIA402TargetState)
|
||||||
svControlWord.SetValue((ushort)0x0007);
|
{
|
||||||
break;
|
case CIA402States.SWITCH_ON_DISABLED:
|
||||||
}
|
svControlWord.SetValue((ushort)0x0000);
|
||||||
break;
|
break;
|
||||||
case CIA402States.SWITCHED_ON:
|
case CIA402States.SWITCHED_ON:
|
||||||
switch (CIA402TargetState)
|
case CIA402States.OPERATION_ENABLED:
|
||||||
{
|
svControlWord.SetValue((ushort)0x0007);
|
||||||
case CIA402States.SWITCH_ON_DISABLED:
|
break;
|
||||||
case CIA402States.READY_TO_SWITCH_ON:
|
}
|
||||||
svControlWord.SetValue((ushort)0x0006);
|
break;
|
||||||
break;
|
case CIA402States.SWITCHED_ON:
|
||||||
case CIA402States.OPERATION_ENABLED:
|
switch (CIA402TargetState)
|
||||||
svControlWord.SetValue((ushort)0x000F);
|
{
|
||||||
break;
|
case CIA402States.SWITCH_ON_DISABLED:
|
||||||
}
|
case CIA402States.READY_TO_SWITCH_ON:
|
||||||
break;
|
svControlWord.SetValue((ushort)0x0006);
|
||||||
case CIA402States.OPERATION_ENABLED:
|
break;
|
||||||
switch (CIA402TargetState)
|
case CIA402States.OPERATION_ENABLED:
|
||||||
{
|
svControlWord.SetValue((ushort)0x000F);
|
||||||
case CIA402States.SWITCH_ON_DISABLED:
|
break;
|
||||||
case CIA402States.READY_TO_SWITCH_ON:
|
}
|
||||||
svControlWord.SetValue((ushort)0x0006);
|
break;
|
||||||
break;
|
case CIA402States.OPERATION_ENABLED:
|
||||||
case CIA402States.SWITCHED_ON:
|
switch (CIA402TargetState)
|
||||||
svControlWord.SetValue((ushort)0x0007);
|
{
|
||||||
break;
|
case CIA402States.SWITCH_ON_DISABLED:
|
||||||
}
|
case CIA402States.READY_TO_SWITCH_ON:
|
||||||
break;
|
svControlWord.SetValue((ushort)0x0006);
|
||||||
|
break;
|
||||||
|
case CIA402States.SWITCHED_ON:
|
||||||
|
svControlWord.SetValue((ushort)0x0007);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CIA402TargetState = CIA402States.UNDEFINED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DriveMode == DriveMode.UNDEFINED)
|
if (DriveMode == DriveMode.UNDEFINED)
|
||||||
DriveMode = DriveMode.TORQUE;
|
DriveMode = DriveMode.SPEED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DriveStates DriveState
|
public override DriveStates DriveState
|
||||||
|
@ -182,6 +200,7 @@ namespace ln.ethercat.controller.drives
|
||||||
case CIA402ModesOfOperation.CYCLIC_SYNC_POSITION:
|
case CIA402ModesOfOperation.CYCLIC_SYNC_POSITION:
|
||||||
return DriveMode.POSITION;
|
return DriveMode.POSITION;
|
||||||
case CIA402ModesOfOperation.CYCLIC_SYNC_VELOCITY:
|
case CIA402ModesOfOperation.CYCLIC_SYNC_VELOCITY:
|
||||||
|
case CIA402ModesOfOperation.VL_VELOCITY_MODE:
|
||||||
return DriveMode.SPEED;
|
return DriveMode.SPEED;
|
||||||
case CIA402ModesOfOperation.CYCLIC_SYNC_TORQUE:
|
case CIA402ModesOfOperation.CYCLIC_SYNC_TORQUE:
|
||||||
return DriveMode.TORQUE;
|
return DriveMode.TORQUE;
|
||||||
|
@ -196,7 +215,7 @@ namespace ln.ethercat.controller.drives
|
||||||
ModeOfOperation = CIA402ModesOfOperation.CYCLIC_SYNC_POSITION;
|
ModeOfOperation = CIA402ModesOfOperation.CYCLIC_SYNC_POSITION;
|
||||||
break;
|
break;
|
||||||
case DriveMode.SPEED:
|
case DriveMode.SPEED:
|
||||||
ModeOfOperation = CIA402ModesOfOperation.CYCLIC_SYNC_VELOCITY;
|
ModeOfOperation = CIA402ModesOfOperation.VL_VELOCITY_MODE;
|
||||||
break;
|
break;
|
||||||
case DriveMode.TORQUE:
|
case DriveMode.TORQUE:
|
||||||
ModeOfOperation = CIA402ModesOfOperation.CYCLIC_SYNC_TORQUE;
|
ModeOfOperation = CIA402ModesOfOperation.CYCLIC_SYNC_TORQUE;
|
||||||
|
@ -214,11 +233,19 @@ namespace ln.ethercat.controller.drives
|
||||||
|
|
||||||
public CIA402ModesOfOperation ModeOfOperation {
|
public CIA402ModesOfOperation ModeOfOperation {
|
||||||
get => (ECMaster.EthercatState==ECSlaveState.OPERATIONAL) ? (CIA402ModesOfOperation)(svModesOfOperationDisplay?.GetValue<sbyte>() ?? 0) : CIA402ModesOfOperation.NO_MODE_CHANGE;
|
get => (ECMaster.EthercatState==ECSlaveState.OPERATIONAL) ? (CIA402ModesOfOperation)(svModesOfOperationDisplay?.GetValue<sbyte>() ?? 0) : CIA402ModesOfOperation.NO_MODE_CHANGE;
|
||||||
set => svModesOfOperation.SetValue((sbyte)value);
|
set {
|
||||||
|
svModesOfOperation.SetValue((sbyte)value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double ActualPosition => (svActualPosition?.GetValue<int>() ?? 0) ;
|
public override double ActualPosition => (svActualPosition?.GetValue<int>() ?? 0) ;
|
||||||
public override double ActualSpeed => (double)(svActualSpeed?.GetValue<int>() ?? 0) / (1000.0 * MotorMaxSpeed);
|
public override double ActualSpeed {
|
||||||
|
get {
|
||||||
|
if (ModeOfOperation == CIA402ModesOfOperation.CYCLIC_SYNC_VELOCITY)
|
||||||
|
return (double)(svActualSpeed?.GetValue<int>() ?? 0) / (1000.0 * MotorMaxSpeed);
|
||||||
|
return (double)(svVLActualVelocity?.GetValue<short>() ?? 0) / MotorMaxSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
public override double ActualTorque => (double)(svActualTorque?.GetValue<short>() ?? 0) / 1000.0;
|
public override double ActualTorque => (double)(svActualTorque?.GetValue<short>() ?? 0) / 1000.0;
|
||||||
public override double ActualLoad => (double)(svActualCurrent?.GetValue<short>() ?? 0) / 1000.0;
|
public override double ActualLoad => (double)(svActualCurrent?.GetValue<short>() ?? 0) / 1000.0;
|
||||||
|
|
||||||
|
@ -228,8 +255,16 @@ namespace ln.ethercat.controller.drives
|
||||||
}
|
}
|
||||||
|
|
||||||
public override double TargetSpeed {
|
public override double TargetSpeed {
|
||||||
get => (double)svTargetSpeed.GetValue<int>() / (1000.0 * MotorMaxSpeed);
|
get {
|
||||||
set => svTargetSpeed.SetValue((int)(value * (1000.0 * MotorMaxSpeed)));
|
if (ModeOfOperation == CIA402ModesOfOperation.CYCLIC_SYNC_VELOCITY)
|
||||||
|
return (double)svTargetSpeed.GetValue<int>() / (1000.0 * MotorMaxSpeed);
|
||||||
|
return (double)(svVLTargetVelocity?.GetValue<short>() ?? 0) / MotorMaxSpeed;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
if (ModeOfOperation == CIA402ModesOfOperation.CYCLIC_SYNC_VELOCITY)
|
||||||
|
svTargetSpeed.SetValue((int)(value * (1000.0 * MotorMaxSpeed)));
|
||||||
|
svVLTargetVelocity.SetValue((short)(value * MotorMaxSpeed));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public override double TargetTorque {
|
public override double TargetTorque {
|
||||||
get => (double)svTargetTorque.GetValue<short>() / 1000.0;
|
get => (double)svTargetTorque.GetValue<short>() / 1000.0;
|
||||||
|
|
|
@ -2,11 +2,8 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO.Ports;
|
using System.IO.Ports;
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using ln.logging;
|
using ln.ethercat.controller.drives;
|
||||||
using ln.type;
|
|
||||||
|
|
||||||
namespace ln.ethercat.controller.remote
|
namespace ln.ethercat.controller.remote
|
||||||
{
|
{
|
||||||
|
@ -33,15 +30,29 @@ namespace ln.ethercat.controller.remote
|
||||||
LOAD100 = (1<<15),
|
LOAD100 = (1<<15),
|
||||||
ALL = -1
|
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; }
|
||||||
|
|
||||||
SerialPort serialPort;
|
SerialPort serialPort;
|
||||||
|
|
||||||
bool stopReceiverThread;
|
bool stopReceiverThread;
|
||||||
Thread threadReceiver;
|
Thread threadReceiver;
|
||||||
|
|
||||||
|
public double MainTarget { get; set; }
|
||||||
|
public double FeedTarget { get; set; }
|
||||||
|
|
||||||
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)
|
||||||
|
@ -77,12 +88,50 @@ namespace ln.ethercat.controller.remote
|
||||||
if (Controller.ECMaster.DriveControllers[0].ActualLoad >= 1)
|
if (Controller.ECMaster.DriveControllers[0].ActualLoad >= 1)
|
||||||
leds |= StupidLEDs.LOAD100;
|
leds |= StupidLEDs.LOAD100;
|
||||||
SetLEDs(leds);
|
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);
|
||||||
|
} 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);
|
||||||
|
} 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);
|
||||||
|
} else {
|
||||||
|
Controller.ECMaster.DriveControllers[1].DriveMode = DriveMode.TORQUE;
|
||||||
|
Controller.RemoteUpdateTarget(1, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ControllerStates.ENABLING:
|
case ControllerStates.ENABLING:
|
||||||
break;
|
break;
|
||||||
case ControllerStates.DISABLING:
|
case ControllerStates.DISABLING:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Receiver()
|
void Receiver()
|
||||||
|
@ -92,18 +141,25 @@ namespace ln.ethercat.controller.remote
|
||||||
string rxLine = serialPort.ReadLine();
|
string rxLine = serialPort.ReadLine();
|
||||||
//Logging.Log(LogLevel.DEBUGDETAIL, rxLine);
|
//Logging.Log(LogLevel.DEBUGDETAIL, rxLine);
|
||||||
if (rxLine.Length >= 6)
|
if (rxLine.Length >= 6)
|
||||||
{
|
{
|
||||||
ushort av = ushort.Parse(rxLine.Substring(2,4), System.Globalization.NumberStyles.HexNumber);
|
ushort av = 0;
|
||||||
|
ushort.TryParse(rxLine.Substring(2,4), System.Globalization.NumberStyles.HexNumber, null, out av);
|
||||||
|
|
||||||
switch (rxLine[0])
|
switch (rxLine[0])
|
||||||
{
|
{
|
||||||
case 'A':
|
case 'A':
|
||||||
int drive = rxLine[1] - '0';
|
int drive = rxLine[1] - '0';
|
||||||
if (drive == 0) drive = 1;
|
|
||||||
else if (drive == 1) drive = 2;
|
|
||||||
else if (drive == 2) drive = 0;
|
|
||||||
double rel = (double)av / 65535;
|
double rel = (double)av / 65535;
|
||||||
if ((drive >= 0) && (drive < Controller.ECMaster.DriveControllers.Length))
|
switch (drive)
|
||||||
Controller.RemoteUpdateTarget(drive, rel);
|
{
|
||||||
|
case 0:
|
||||||
|
FeedTarget = rel;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
MainTarget = rel;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Controller.RemoteTriggerWatchdog();
|
||||||
break;
|
break;
|
||||||
case 'B':
|
case 'B':
|
||||||
switch (rxLine[1])
|
switch (rxLine[1])
|
||||||
|
@ -115,19 +171,36 @@ namespace ln.ethercat.controller.remote
|
||||||
if (Controller.ControllerState == ControllerStates.FAULT)
|
if (Controller.ControllerState == ControllerStates.FAULT)
|
||||||
Controller.RemoteAction(CRActions.CLEARFAULT);
|
Controller.RemoteAction(CRActions.CLEARFAULT);
|
||||||
else if (Controller.ControllerState == ControllerStates.READY)
|
else if (Controller.ControllerState == ControllerStates.READY)
|
||||||
|
{
|
||||||
|
Controller.ECMaster.DriveControllers[0].DriveMode = DriveMode.SPEED;
|
||||||
Controller.RemoteAction(CRActions.ENABLE);
|
Controller.RemoteAction(CRActions.ENABLE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
Controller.RemoteAction(CRActions.DISABLE);
|
Controller.RemoteAction(CRActions.DISABLE);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
switch (av)
|
||||||
|
{
|
||||||
case 3:
|
case 3:
|
||||||
// ToDo: Feeder left
|
FeederOperation = FeederOperation.LEFT;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
// ToDo: Feeder right
|
FeederOperation = FeederOperation.RIGHT;
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
// ToDo: cycle drilling
|
FeederOperation = FeederOperation.TORQUE;
|
||||||
|
break; }
|
||||||
|
break;
|
||||||
|
case 'U':
|
||||||
|
switch (av)
|
||||||
|
{
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 14:
|
||||||
|
FeederOperation = FeederOperation.NONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue