Avatar

Please consider registering
guest

sp_LogInOut Log In sp_Registration Register

Register | Lost password?
Advanced Search

— Forum Scope —




— Match —





— Forum Options —





Minimum search word length is 3 characters - maximum search word length is 84 characters

sp_Feed Topic RSS sp_TopicIcon
History Variable. When is a history variable recorderd?
February 20, 2017
15:18, EET
Avatar
kapsl
Member
Members
Forum Posts: 57
Member Since:
December 20, 2016
sp_UserOfflineSmall Offline

Hi,
we currently have the problem, that we historize two nodes (of type double array). The function to set a value is always called for every node, so there should be exactly the same nr. of history variables. But there isn’t. Is there some internal function that checks if the value has changed since the last time and only then adds a history record? How does this function look? Is there some epsion value for doubles?

Thanks,
lg Manu

February 21, 2017
15:43, EET
Avatar
Jouni Aro
Moderator
Moderators
Forum Posts: 1010
Member Since:
December 21, 2011
sp_UserOfflineSmall Offline

The SDK does not define any history storage. The only history storage is provided as part of the SampleConsoleServer. It is only provided as an example of a very basic history storage.

So, if you have copied your implementation from the example, you can also verify it directly how it works and modify it according to your needs.

UaVariableNode (or CacheVariable) filters the changes, if you change the value of the variable. It only provides DataChange notifications, when the value actually changes. there is no epsilon.

March 7, 2017
14:52, EET
Avatar
kapsl
Member
Members
Forum Posts: 57
Member Since:
December 20, 2016
sp_UserOfflineSmall Offline

Is there a way to tell the history manager to listen on a e.g. serverTimestampChange? I did only find the addDataChangeListener() for the UaVariable, so how could I track values in the history, where the data hasn’t changed?

March 8, 2017
11:58, EET
Avatar
Jouni Aro
Moderator
Moderators
Forum Posts: 1010
Member Since:
December 21, 2011
sp_UserOfflineSmall Offline

The plain change of ServerTimestamp will not trigger any change from the UaVariableNode. But if the SourceTimestamp changes, you do get a data change from the variable.

However, I was not quite sure what you want to accomplish. Typically you only need the changes in the history and you can assume values haven’t changed after that (in stepped mode). If you want to interpolate values between the changes, then it would make sense to store the in-between values even when they haven’t changed. But I would trust the SourceTimestamp in this case as well.

March 9, 2017
15:31, EET
Avatar
kapsl
Member
Members
Forum Posts: 57
Member Since:
December 20, 2016
sp_UserOfflineSmall Offline

We use the codegenerator. How can we force a reset of the sourceTimestamp there?

The idea is to have several values collected at a fixed sampling rate. E.g. 30ms. If one value doesn’t change in some timespan, we nevertheless want a datapoint because elseway the time-dimension is not constant between different collected values.

March 10, 2017
12:06, EET
Avatar
Jouni Aro
Moderator
Moderators
Forum Posts: 1010
Member Since:
December 21, 2011
sp_UserOfflineSmall Offline

By default, whenever you set a new value to a variable, it will get a new SourceTimestamp (respective to current time).

If you still think it does not do what you are expecting, you will need to explain a bit more how you are doing it.

March 10, 2017
12:23, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Hmm I looked this now and it actually seems to be a bug.

The setValue accepts raw values, Variants and DataValues, and in the case of the 2 first ones it does not set the sourcetimestamp correctly if the value is equal to previous one.

As a workaround until next release you could use the setValue by providing complete DataValue for which you can set the timestamps.

i.e. for generated nodes XXXTypeNode.getYYYNode().setValue(DataValue)

– Bjarne

March 13, 2017
16:55, EET
Avatar
kapsl
Member
Members
Forum Posts: 57
Member Since:
December 20, 2016
sp_UserOfflineSmall Offline

Hi and thanks for your answer!
I can’t confirm this. I did now try the following, but I still don’t get the same nr. of values:

Variant myVariant = new Variant(value);
DataValue myDataValue = new DataValue();
myDataValue.setValue(myVariant);
myDataValue.setStatusCode(StatusCode.GOOD);
myDataValue.setServerTimestamp(DateTime.currentTime());
myDataValue.setSourceTimestamp(DateTime.currentTime());
node.setValue(myDataValue);

lg Manu

March 21, 2017
11:22, EET
Avatar
kapsl
Member
Members
Forum Posts: 57
Member Since:
December 20, 2016
sp_UserOfflineSmall Offline

Does anybody have a solution for this?

March 22, 2017
14:26, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Hi,

Can you please explain exactly how you are observing the values of the node?

– Bjarne

March 22, 2017
16:15, EET
Avatar
kapsl
Member
Members
Forum Posts: 57
Member Since:
December 20, 2016
sp_UserOfflineSmall Offline

Hi Bjarne,
sure:
private final ScheduledExecutorService simulator = Executors
.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
simulator.scheduleAtFixedRate(this, 0, 25, TimeUnit.MILLISECONDS);

in the run() method, which is called every 25 milliseconds:
updateAxisAngles();
updateTorques();

The method looks like:
public void setAllAxisAngle(JointPosition axis) throws StatusException {
Axis axis = AddressSpace.getAxisNode();

// Be careful not getting an out of bounds error
ArrayList newValues = new ArrayList();

for (int i = 0; i < axis.getAxisCount(); i++)
newValues.add(axis.get(i));

Double[] newValuesAr = new Double[newValues.size()];
axis.setValues(newValues.toArray(newValuesAr));
}

updateTorques works the same

and axis.setValues is generated by the jave codegenerator. I tried to change the implementation as explained in the last post, but without success. In the end i get a different number of axis and torques…

Thanks,
lg manu

March 22, 2017
16:50, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Ok that explains how you set the values. How are you observing them?

Can show the place/how “In the end i get a different number of axis and torques…”

Can you show the code where ” … so there should be exactly the same nr. of history variables.” i.e. I would need steps to reproduce this.

Mentioning this just in case.. based on the words you are using I would assume you are talking about the server side. If you are reading these from the client side, then of course this can happen as based on the code above you update axis first and then torgues.

March 23, 2017
9:57, EET
Avatar
kapsl
Member
Members
Forum Posts: 57
Member Since:
December 20, 2016
sp_UserOfflineSmall Offline

Hi,
ok on client side I use python-opcua. And i do a

for node in nodes_to_watch:
node_history = node.read_raw_history(starttime=starttime, endtime=endtime)

Start and endtime do not change. And finally I get a different number of history elements for the two nodes. I would agree with you, if this would just be a difference of one, then maybe we were reading exactly between writing the one and the other node on server side. But when recording longer time, the numbers diverge by 200 or so.

lg

March 23, 2017
10:39, EET
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

Just to be clear, how are you recording and storing the history data and returning it to the client (i.e. what are you doing onReadRaw call if you implemented HistoryManagerListener or readRaw if you are extending HistoryManager instead)?

And to understand you application needs better: what are the requirements for the history data, i.e. must it survive a restart of the server?

March 27, 2017
11:05, EEST
Avatar
kapsl
Member
Members
Forum Posts: 57
Member Since:
December 20, 2016
sp_UserOfflineSmall Offline

Hi Bjarne,
The requirements for the history data:
– It must not survive a restart
– We have to collect data from a device at a fix time interval e.g. 25ms. For every timestep several nodes are written. E.g. one node (an array of 7 axis values) another node an array of (6 force values).

The code is mainly from the example server. So at the history manager listener there is for onReadRaw:

ValueHistory history = variableHistories.get(node);

if (history != null) {
List values = new ArrayList();

int firstIndex = continuationPoint == null ? 0 : (Integer) continuationPoint;

Integer newContinuationPoint = history.readRaw(startTime, endTime, numValuesPerNode.intValue(),
returnBounds, firstIndex, values);
historyData.setDataValues(values.toArray(new DataValue[values.size()]));

return newContinuationPoint;
}

return null;

In ValueHistory we have:
public Integer readRaw(DateTime startTime, DateTime endTime, int maxValues, boolean returnBounds, int firstIndex,
List history) {
int i = 0;
boolean startTimeDefined = startTime.compareTo(DateTime.MIN_VALUE) > 0;
boolean endTimeDefined = endTime.compareTo(DateTime.MIN_VALUE) > 0;

if (startTimeDefined || !endTimeDefined)
for (DataValue value : values) {
DateTime t = value.getSourceTimestamp();

if (t == null)
t = value.getServerTimestamp();

final int compareToEnd = endTimeDefined ? t.compareTo(endTime) : -1;

if ((compareToEnd > 0) || (!returnBounds && (compareToEnd == 0)))
break;
else {
final int compareToStart = t.compareTo(startTime);

if ((compareToStart > 0) || (returnBounds && (compareToStart == 0))) {
if (i >= firstIndex)
history.add(value);

i++;

if (history.size() == maxValues)
return i;
}
}
}
else
for (int j = values.size() – 1; j >= 0; j–) {
DataValue value = values.get(j);
DateTime t = value.getSourceTimestamp();

if (t == null)
t = value.getServerTimestamp();

final int compareToEnd = t.compareTo(endTime);
if ((compareToEnd > 0) || (!returnBounds && (compareToEnd == 0)))
continue;
else {
if (i >= firstIndex)
history.add(value);

i++;

if (history.size() == maxValues)
return i;
}
}

return null;
}

and readAtTimes() is:
public DataValue[] readAtTimes(DateTime[] reqTimes) {
if (reqTimes == null)
return null;

DataValue[] values = new DataValue[reqTimes.length];

for (int i = 0; i < reqTimes.length; i++) {
DateTime t = reqTimes[i];

// Stepped interpolation used to get values
DataValue v = getValue(t);
values[i] = new DataValue(v == null ? null : v.getValue(),
v == null ? new StatusCode(StatusCodes.Bad_NoData) : v.getStatusCode(), t, UnsignedShort.ZERO, null,
null);
}

return values;
}

April 4, 2017
10:46, EEST
Avatar
Bjarne Boström
Moderator
Moderators
Forum Posts: 983
Member Since:
April 3, 2012
sp_UserOfflineSmall Offline

At least as a workaround, you could try putting the values directly to the history storage at the same time you are putting it to the node. At least to check that the values/number of values are correct on the server side.

Forum Timezone: Europe/Helsinki

Most Users Ever Online: 518

Currently Online:
13 Guest(s)

Currently Browsing this Page:
1 Guest(s)

Top Posters:

hbrackel: 135

pramanj: 86

Francesco Zambon: 81

rocket science: 77

Ibrahim: 76

Sabari: 62

kapsl: 57

gjevremovic: 49

Xavier: 43

fred: 41

Member Stats:

Guest Posters: 0

Members: 683

Moderators: 16

Admins: 1

Forum Stats:

Groups: 3

Forums: 15

Topics: 1467

Posts: 6261

Newest Members:

digitechroshni, LouieWreve, Kickbiche, karrimacvitie5, graciela2073, sagarchau, elviralangwell4, Donnavek, Eddiefauth, DonaldPooma

Moderators: Jouni Aro: 1010, Otso Palonen: 32, Tuomas Hiltunen: 5, Pyry: 1, Petri: 0, Bjarne Boström: 983, Heikki Tahvanainen: 402, Jukka Asikainen: 1, moldzh08: 0, Jimmy Ni: 26, Teppo Uimonen: 21, Markus Johansson: 42, Niklas Nurminen: 0, Matti Siponen: 321, Lusetti: 0, Ari-Pekka Soikkeli: 5

Administrators: admin: 1