Skip to content
Snippets Groups Projects
Commit e2fbe2a6 authored by Matthias Stefan Bodenbenner's avatar Matthias Stefan Bodenbenner
Browse files

updated to newest soil version and updated evaluations scripts

parent 7fcf8397
No related branches found
No related tags found
No related merge requests found
Showing
with 502 additions and 20 deletions
......@@ -49,3 +49,11 @@ Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation)
Funded by the Deutsche Forschungsgemeinschaft (DFG, German Research Foundation) under Project-ID 432233186 -- AIMS.
## License of used third-party libraries
| Library | License |
|----------|-----------------------------|
| numpy | BSD License |
| requests | BSD License |
| toml | MIT License |
| wzl-udi | MIT License |
\ No newline at end of file
import tool;
import toolChanger;
import part;
enum CoordinateSystems {
MachineCsy
MovableMachineCsy
MultipleArmCsy
RotaryTableVarCsy
PartCsy
}
variable ActiveCsy {
name: "ActiveCsy"
description: "The currently active coordinate system."
datatype: enum
dimension: []
range: CoordinateSystems
}
component CartCMM {
name: "CartCMM"
description: "Cartesian Coordinate Measuring Machine"
components:
toolChanger.ToolChanger toolChanger
part.Part part
parameters:
tool.Id activeTool
}
\ No newline at end of file
import cartCMM;
function AbortE {
name: "AbortE"
description: "Aborts all pending transactions and stops the machine from moving."
}
function ClearAllErrors {
name: "ClearAllErrors"
description: "Is called to recover from an error."
}
component Ipp {
name: "I++"
description: "The top-level component of the Server."
components:
cartCMM.CartCMM cmm
functions:
AbortE abortE
ClearAllErrors clearAllErrors
}
interface Ipp IppServer {}
\ No newline at end of file
@prefix quantitykind: <http://qudt.org/vocab/quantitykind/> ;
@prefix unit: <http://qudt.org/vocab/unit/> ;
variable Temperature defines <quantitykind:Temperature> {
name: "Temperature"
description: "Current temperature of the part."
datatype: float
dimension: []
range: (-50, 200)
unit: <unit:DEG_C>
}
variable Approach defines <quantitykind:Distance>{
name: "Approach"
description: "Currently specified approach distance of the part."
datatype: float
dimension: []
range: (0, 500)
unit: <unit:MilliM>
}
component Part {
name: "Part"
description: "Soil representation of a Part."
measurements:
Temperature temperature
parameters:
Approach approach
}
\ No newline at end of file
@prefix quantitykind: <http://qudt.org/vocab/quantitykind/> ;
@prefix unit: <http://qudt.org/vocab/unit/> ;
variable Name {
name: "Name"
description: "Name of a Tool"
datatype: string
dimension: []
}
variable Id {
name: "Id"
description: "Id of a Tool"
datatype: string
dimension: []
}
# variable PositionList {
# name: "PositionList"
# description: "List of Points used for ScanOnCurve"
# datatype: float
# dimension: [0, 3]
# }
variable Position defines <quantitykind:CartesianCoordinates> {
name: "Position"
description: "Current position of the tool, consisting of the I++ X, Y and Z values."
datatype: float
dimension: [3]
unit: <unit:MilliM>
}
function ScanOnCurve {
name: "ScanOnCurve"
description: "Function that issues a ScanOnCurve command on the I++ Server"
arguments:
PositionList posL
}
function PtMeas {
name: "PtMeas"
description: "Function that issues a PtMeas command on the I++ Server"
arguments:
Position pos
}
component Tool {
name: "Tool"
description: "The currently active Tool."
measurements:
Position pos
parameters:
constant Name name
constant Id id
PositionList posL
functions:
PtMeas ptMeas
ScanOnCurve scanOnCurve
}
\ No newline at end of file
import tool;
function EnumTools {
name: "EnumTools"
description: "Function that issues an EnumTools command on the I++ server."
}
function ChangeTool {
name: "EnumTools"
description: "Function that issues an ChangeTool command on the I++ server."
arguments:
tool.Id tool_id
}
component ToolChanger {
name: "ToolChanger"
description: "ToolChanger component"
components:
dynamic tool.Tool tools
functions:
EnumTools enumTools
ChangeTool changeTool
}
\ No newline at end of file
cd scripts
:: python generate.py ipp.soil -g shell -s -hwc
python generate.py robot.soil -g remote -s -hwc
python generate.py lasertracker.soil -g remote -s -hwc
python generate.py monitoring.soil -g remote -s -hwc
......
numpy
requests
toml
wzl-udi==9.3.8
numpy==1.24.2
requests==0.10.2
toml==
wzl-udi==10.0.0
......@@ -2,7 +2,7 @@ numpy
requests
toml
tqdm
wzl-udi==9.3.3
wzl-udi==10.0.0
kaleido
plotly
pandas
\ No newline at end of file
......@@ -71,6 +71,6 @@ if __name__ == '__main__':
stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
print(stdout.decode())
print(stderr.decode())
print(stderr.decode('latin-1'))
else:
print(f'Generator type "{args.generator}" is unknown, must be one of "shell", "local", "remote".')
......@@ -9,7 +9,7 @@ from assessment.framework import Framework, AssessmentError, FUJI, FAIRChecker
SRC = os.path.join('.')
OUT = os.path.join('..', 'out')
PROFILES = True
PROFILES = False
METADATA = True
......
......@@ -8,14 +8,14 @@ SRC = os.path.join('..', 'src')
ASSESSMENTS = os.path.join('..', 'out')
OUT = os.path.join('..', 'out')
PROFILES = True
PROFILES = False
METADATA = True
if __name__ == '__main__':
dummies = ['lasertracker', 'monitoring', 'robot']
profile_scores = pandas.DataFrame()
metadata_scores = {'f-uji': [], 'fair-checker': []}
metadata_scores = pandas.DataFrame(columns=["framework", "dummy", "principle", "value"])
for dummy in dummies:
......@@ -26,15 +26,18 @@ if __name__ == '__main__':
for framework in frameworks:
if PROFILES:
profile_scores[framework.name] += [
framework.evaluate(os.path.join(ASSESSMENTS, framework.name, dummy, 'profiles'))]
framework.evaluate(os.path.join(ASSESSMENTS, framework.name, dummy, 'profiles'), dummy)
if METADATA:
metadata_scores[framework.name] += [
framework.evaluate(os.path.join(ASSESSMENTS, framework.name, dummy, 'profiles'))]
score = framework.evaluate(os.path.join(ASSESSMENTS, framework.name, dummy, 'metadata'), dummy)
metadata_scores = pandas.concat([metadata_scores, score], ignore_index=True)
average_profile_scores = [profile_scores[key].mean() for key in profile_scores]
average_metadata_scores = [metadata_scores[key].mean() for key in metadata_scores]
average_scores = metadata_scores.groupby(['framework', 'principle'], as_index=False).agg({'value': 'mean'})
Framework.visualize(average_profile_scores, list(profile_scores.keys()), 'profiles.png')
Framework.visualize(average_metadata_scores, list(profile_scores.keys()), 'metadata.png')
print(average_scores)
# average_profile_scores = [profile_scores[key].mean() for key in profile_scores]
# average_metadata_scores = [metadata_scores[key].mean() for key in metadata_scores]
# Framework.visualize(average_profile_scores, list(profile_scores.keys()), 'profiles.png')
Framework.visualize(metadata_scores, 'metadata.png')
from scripts.gen.ipp.tool.com_tool import COMToolTOP
from scripts.gen.ipp.hwc.device import Device
class COMTool(COMToolTOP):
def __init__(self, device: Device, name: str = "", id: str = "", posl: list[float] = None ):
COMToolTOP.__init__(self, device, name, id)
self._device = device
def fun_ptmeas(self, arg_pos):
self._device.pt_meas(arg_pos[0], arg_pos[1], arg_pos[2])
def scanoncurve(self, posl):
self._device.scanoncurve(posl)
def get_mea_pos(self):
return self._device.position
import asyncio
import time
from scripts.gen.ipp.device import DeviceTOP
from threading import Thread
from . import ipp_client
import re
class Tool(object):
def __init__(self, position):
self._position = position
def update(self, position):
self._position = position
@property
def position(self):
return self._position
class Device(DeviceTOP, Thread):
def __init__(self):
DeviceTOP.__init__(self)
Thread.__init__(self)
self._x = 0
self._y = 0
self._z = 0
self._tool = Tool(self.position)
self._error = False
self._ipp_client = None
async def goto(self, x, y, z):
await self._ipp_client.transaction("GoTo(X(" + x + "), Y(" + y + "), Z(" + z + "))", False)
def pt_meas(self, x, y, z):
self._ipp_client.transaction("PtMeas(X(" + str(x) + "), Y(" + str(y) + "), Z(" + str(z) + "))", False)
@property
def position(self):
return [self._x, self._y, self._z]
def run(self):
self._ipp_client = ipp_client.IPPClient(self)
self._ipp_client.start()
time.sleep(1)
self._ipp_client.transaction("StartSession()", False)
self._ipp_client.transaction("PtMeas(X(1), Y(2), Z(3))", False)
self._ipp_client.transaction("GoTo(X(1), Y(2), Z(3))", False)
for i in range(1000):
self._ipp_client.transaction("ABC(1,2,3)", False)
self._ipp_client.transaction("OnMoveReport(X(), Y(), Z())", True)
def stop(self):
loop = asyncio.get_event_loop()
loop.run_until_complete(self._ipp_client.transaction("EndSession()", False))
dataformat = 'json'
[tcp]
address='localhost'
port=1294
\ No newline at end of file
from __future__ import annotations
import socket
from threading import Thread
import typing
from . import transaction
if typing.TYPE_CHECKING:
from .device import Device
class UnexpectedTagError(Exception):
def __init__(self):
self.message = "The received message contains an unexpected tag."
class MissingACKError(Exception):
def __init__(self):
self.message = "Was expecting an ACK response but received something else."
class MissingTransactionCompleteResponseError(Exception):
def __init__(self):
self.message = "Transaction complete response is missing."
class DaemonNonDataMessage(Exception):
def __init__(self):
self.message = "Received a daemon message that is not a data message!"
class IPPClient(Thread):
def __init__(self, device_i: Device):
Thread.__init__(self)
self._socket = None
self._active = False
self._command_tag = 1
self._transaction_log = {}
self._data_log = {}
self._daemon_log = {}
self._active_streams = []
self._device = device_i
def _handle_event(self, tag, message_type, message_body):
non_event_tag = "0" + tag[1:5]
if non_event_tag in self._active_streams:
daemon = self._transaction_log.get(non_event_tag)
if message_type != "#":
raise DaemonNonDataMessage()
daemon['cb'].update_device(message_body.split(","))
def _parse_message(self, message):
print("<-- " + message)
message = message.split(" ")
tag = message[0]
message_type = message[1]
if tag[0] == "E":
self._handle_event(tag, message_type, "".join(message[2:]))
return
transaction = self._transaction_log.get(tag)
if not transaction['ACK']:
if message_type == '&':
transaction['ACK'] = True
return
else:
raise MissingACKError()
if message_type == '#':
self._data_log[tag + '#' + transaction['uuid']].append(message[::2])
return
if message_type == '%':
if not transaction['daemon']:
self._transaction_log.pop(tag)
return
return
def _send(self, message):
print("--> " + message.decode())
self._socket.sendall(message)
def transaction(self, command, streams):
tag = str(self._command_tag).zfill(5)
command_name = command.split('(')[0]
if streams:
self._active_streams.append(tag)
# Add transaction to pending transaction log
self._transaction_log[tag] = {
'ACK': False,
'uuid': command,
'daemon': streams,
'cb': transaction.create(command_name, tag, self._device)
}
self._send(str.encode(tag + " " + command + "\n"))
self._command_tag = self._command_tag + 1
def _listen(self):
buffer = []
stitch = False
while True:
if (len(buffer) > 0 and not stitch) or (len(buffer) > 1):
self._parse_message(buffer[0])
buffer.pop(0)
continue
data, _ = self._socket.recvfrom(1024)
data = data.decode()
buffer = buffer + (data.splitlines())
if stitch:
buffer[0:2] = ["".join(buffer[0:2])]
stitch = False
if len(data) > 0:
if data[-1] != '\n':
stitch = True
def run(self):
self._active = True
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._socket.connect(('localhost', 1294))
listener = Thread(target=self._listen)
listener.start()
from __future__ import annotations
from abc import ABC, abstractmethod
import re
import typing
from sys import modules
if typing.TYPE_CHECKING:
from .device import Device
class TransactionNotImplementedException(Exception):
def __init__(self):
self.message = "Tried to use an unimplemented Transaction."
class Transaction(ABC):
def __init__(self, tag: str, device: Device):
self._tag = tag
self._device = device
@property
def tag(self) -> str:
return self._tag
@abstractmethod
def update_device(self, data):
...
class OnMoveReportTransaction(Transaction):
def __init__(self, tag: str, device: Device):
Transaction.__init__(self, tag, device)
def update_device(self, data):
print("OnMoveReport update: " + '[%s]' % ', '.join(map(str, data)))
for data_point in data:
axis = data_point.split("(")[0]
value = re.findall(r"-?\d+\.\d+", data_point)
value = value[0]
match axis:
case "X":
self._device._x = float(value)
case "Y":
self._device._y = float(value)
case "Z":
self._device._z = float(value)
# self._tool.update([self._x, self._y, self._z])
class StartSessionTransaction(Transaction):
def __init__(self, tag: str, device: Device):
Transaction.__init__(self, tag, device)
def update_device(self, data):
pass
class PtMeasTransaction(Transaction):
def __init__(self, tag: str, device: Device):
Transaction.__init__(self, tag, device)
def update_device(self, data):
pass
class ScanOnCurveTransaction(Transaction):
def __init__(self, tag: str, device: Device):
Transaction.__init__(self, tag, device)
def update_device(self, data):
pass
class GoToTransaction(Transaction):
def __init__(self, tag: str, device: Device):
Transaction.__init__(self, tag, device)
def update_device(self, data):
pass
def create(command: str, tag: str, device: Device) -> Transaction | None:
module = modules[__name__]
try:
transaction = getattr(module, '{}Transaction'.format(command))(tag, device)
except Exception:
print("Unknown command: " + '"' + command + '"')
print("No callback registered.")
return None
return transaction
import toml
import start
from hwc.device import Device
from com_ipp import COMIpp
if __name__ == '__main__':
device = Device()
soilClient = COMIpp(device)
device.start()
start.start(soilClient, toml.load('config.toml'), 'model.json')
\ No newline at end of file
......@@ -24,13 +24,13 @@ class COMBase(COMBaseTOP):
self._device.point_to(*par_position)
def get_mea_azimuth(self):
return self._device.azimuth
return self._device.azimuth, random.random() * 10e-10
def get_mea_elevation(self):
return self._device.elevation
return self._device.elevation, random.random() * 10e-10
def get_mea_distance(self):
return self._device.distance
return self._device.distance, random.random() * 10e-9
def get_par_state(self):
return str(self._device.state)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment