cancel
Showing results for 
Search instead for 
Did you mean: 

Sensor Graphics

Genius
Genius

I've been asked to add some visuals for the sensors on a line. We are setting up a Virtual Commission or Emulation where we will be interfacing with a PLC.

 

I've been asked to have a graphic next to the line sensor that will change color whether the sensor is sending an ON or OFF bit to the PLC (true or false). I can concieve doing this the long way by creating an icon or 3D graphic and referencing that object by each and every sensor... that seems like a lot of work. However, I was thinking that PS might have the tools to automate this.

 

I'm thinking that I could write a SimTalk method that could build this graphic and place it based on the position of the sensor. This is what I've come up with so far:

 

param SensorID: integer, Front: boolean
?._3D.addGraphicsGroup("PRS1_"+SensorID,true, true)
?._3D.createSphere(makeArray(?.sensorID(SensorID).Position,.5,?._3D.BaseHeight), 0.25, "PRS1_"+SensorID)

Here I am creating a new 3D graphics group named by the type of sensor (PRS1_) + the Sensor ID number, then I am creating a Sphere that will be placed next to the sensor. My thought is then I will just change the color of the sphere depending on whether the value is true or false. The problem I'm having here is that "?.sensorID(SensorID).Position" doesn't appear to return the Position of the sensor. I'm guessing that it only allows  you to set the Position of the sensor. I tested it by doing a hardcoded test: "print PF_Line1.sensorID(1).Position", but I just get the error: "Error in method '.Models.ClassObjects.PF_Line.PRS1_Method' in line 4: Unknown identifier PF_Line1." PF_Line1 does exist.

 

Does anyone have any incite on how I could get this to work... or any better ideas of how I could have a more graphical representation on what is going on at the sensor?

 

Thank you in advance!

28 REPLIES

Re: Sensor Graphics

Genius
Genius

Well I got the Sphere to show up in the correct position... atleast with this first sensor. I have a feeling that it will fail when the line travels down the Y axis... Any ideas on how to get better placement? I also need to figure out how to change the color still.

 

Anyway, here is my code. I had some typos before:

var lineGrphcsNames := ?._3D.GraphicGroupNames
if lineGrphcsNames.find("PRS1_"+SensorID) = 0
?._3D.addGraphicGroup("PRS1_"+SensorID,true, true)
?._3D.createSphere(makeArray(-?.sensorID(SensorID).Position,0.25,?._3D.BaseHeight), 0.1, "PRS1_"+SensorID)
end

 

Re: Sensor Graphics

Siemens Legend Siemens Legend
Siemens Legend

Change the colour by:

?._3D.setGraphicMaterial(makeArray("GraphicName"), 255, 255, 255, 255, 0, 0.1, "GraphicGroup") -- this would paint the Graphic RED, see details in the help file

To calculate the number for a colour from the RGB values use:

 var i : integer := makergbvalue(255,0,0)

Re: Sensor Graphics

Siemens Phenom Siemens Phenom
Siemens Phenom

Your code works on the assumption that the line has only one segment (which is probably true in all your cases) and that the line was inserted from left to right. If you insert it from left to right and turn the whole object afterwards, the code should still work. Additionally, your segment probably doesn't rise or fall in Z direction. (That could all be taken into account but the more general your code should be, the more complex it will get so I't like to keep the matter restricted but simple)

To take care of the insertion direction, you can use the tangential angle of the polycurve segment:

<obj>._3D.getExtSegments(t) fills the table <t> with the segments of the conveyor <obj>.

After the call, t[1,2] will give you the tangential angle of the segment.

The tridimensional sensor position can no be modified as follows:

Say, your left-to-right values are makeArray(x, y, z). The rotated values then are makeArray(cos(t[1,2]) * x, -sin(t[1,2]) * y, z). That way, your tridimensional sensor position should always be correct in this limited case.

 

On the topic of applying the color to your graphic:

_3D.createSphere(...) returns an integer index that you then can use for your call to _3D.setGraphicMaterial(...) - set the first parameter to makeArray(<return value of createSphere>) to reference it.

Re: Sensor Graphics

Genius
Genius

Thank you Peter for this insite. Actually this line has many segments and has many curves and does change in Z. I've only been testing this code on the first couple of sensors. It does seem to work correctly on these... except the 3rd sensor is on a segment that has a up Z slope, so the Z is incorrect when the graphic is built.

 

I've been nervous to test it on segments further down, because I was pretty sure that it would fail and I wasn't sure how I would handle it.

 

Thank you for your suggestion on using the getExtSegments method. I'll give it a shot and see if I can get something that will work down the rest of the line.

 

 

Re: Sensor Graphics

Genius
Genius

On a multiple segment line, how would I know what segment the current sensor is on? 

 

My guess is that I would have to use a loop and add up the length of each segment until I landed on the one that contained the ?.sensorID(SensorID).Position? Or would there be an easier way to do this?

 

--note--

t[1,2] will return the Tangential angle in degrees, but cos(), and sin() need the value in radians. To convert: 

cos((t[1,2]*(pi/180)))

Re: Sensor Graphics

Siemens Phenom Siemens Phenom
Siemens Phenom

Sorry, you're absolutely correct with the degrees/radian conversion - I did this in my example but forgot to mention that.

 

I'm not entirely sure whether there is an easier way than looping through the segments. At least I know of none.

To calculate the absolute tangential angle, you'll have to sum up the tangential angles and curve angles up to the segment in which the sensor is located. Additionally, to locate the sensor, you'll also need to sum up the segment lengths and check in every loop whether the sensor position is between the last summed up length and the current one.

At least, you can use is the position of the last segment before the sensor - that can be found in columns 7 to 9 of the segments table. You'll need to add these values to the x/y/z values of your graphic position (but you can remove the addition of the base height in that case).

 

To calculate the segment lenghts then, you can use the value in column 6 ("length") for straight segments and radius (column 4) * curveAngle (column 3) * pi / 180 for curve segments. If you also have height offsets (column 6 - delta Z), you'll have to adjust the length by length := sqrt(length*length + dZ*dZ).

Short of vertical curve segments (column 5 is true), this should cover all cases.

Re: Sensor Graphics

Genius
Genius

Thank you Peter! I was surprized when I read your post, because I was in the process of coding about half of what you suggested... It's great to have that confirmation that I'm on the right path!! Thank you for the formula to account for the curves... I still need to implement that. I hadn't even begun to try to work through that. I had enough trouble cleaning out the cobwebs in the geometry part of my brain... fortunately my teachers in HS repeated themselves enough that I heard them inbetween naps. The old y = mx + b and c2 = a2 + b2 came in handy :-)

 

 

Here's what I have so far:

param SensorID: integer, Front: boolean
var lineGrphcsNames := ?._3D.GraphicGroupNames
if lineGrphcsNames.find("PRS1_"+SensorID) = 0 --if not exist
	var t : table
	?._3D.getExtSegments(t)
	--local vars--
	var len : length := 0.0
	var seg : integer := 0
	var tga : real := 0
	var hgt : length := ?._3D.BaseHeight
	var SphrHgt : length := 0
	var SphrX : length := 0
	var m : real := 0
	var senSegPos : length := 0
	--parse through segments before sensor--
	repeat
		seg += 1		        --index++--
		len += t[2,seg]			--add up lengths--
		tga += t[1,seg]			--add up tangential angles--
		hgt += t[6,seg]			--add up height changes--
	until len >= ?.sensorID(SensorID).Position  --repeat until accum length is >= Sensor Position--
	tga := tga*(pi/180)			    --convert deg to radians--
	--calculations for x,y,z placement--
	m := (t[6,seg] / sqrt( pow(t[2,seg],2) - pow(t[6,seg],2)) )		--find slope ΔZ/ΔX on current segment--
	senSegPos := ?.sensorID(SensorID).Position-(len-t[2,seg])		--length position of Sensor on it's segment--
	SphrX := senSegPos / sqrt( pow(m,2) + 1 )				--find x length ; formula ref: http://tinyurl.com/h98acjw--
	SphrHgt := (m*SphrX) + ?._3D.BaseHeight 				--z = mx + b to find Sphere Height--
	SphrX += t[7,1] - t[7,seg-1]  						--add previous segment X, minus first seg (our 0 ref)--
	--build graphic; set init color--
	?._3D.addGraphicGroup("PRS1_"+SensorID,true, true)
	?._3D.createSphere(makeArray(cos(tga)*SphrX,sin(tga)+0.25,SphrHgt), 0.1, "PRS1_"+SensorID)
	?._3D.setGraphicMaterial(makeArray(1), makeRGBValue(160,160,164), makeRGBValue(0,0,0), makeRGBValue(0,0,0), makeRGBValue(0,0,0), 0.0, 0.2, "PRS1_"+SensorID) 	--white; off
end

 

Re: Sensor Graphics

Genius
Genius
Well... Just tested this further down the line (after an elevation change)... way off. Looks like an issue with calculating the Z. Dang, sure would be nice if I could just get the XYZ of the current Sensor Graphic or if I could just access the graphic of the current Sensor.

Re: Sensor Graphics

Genius
Genius

Not sure what the etiquette is on here regarding updates... as far as deleting my outdated code, but here is another update.

 

This is now working on a straight line with Z changes, still need to work on the curves.

param SensorID: integer, Front: boolean
var lineGrphcsNames := ?._3D.GraphicGroupNames
if lineGrphcsNames.find("PRS1_"+SensorID) = 0 --if not exist
	var t : table
	?._3D.getExtSegments(t)
	--local vars--
	var len : length := 0.0
	var seg : integer := 0
	var tga : real := 0
	var hgt : length := ?._3D.BaseHeight
	var SphrHgt : length := 0
	var SphrX : length := 0
	var m : real := 0
	var senSegPos : length := 0
	var xCor : length := 0
	--parse through segments before sensor--
	repeat
		seg += 1				--index++--
		if seg > t.MaxYDim		--if beyond scope of table--
			seg -= 1
			exitloop
		end
		len += t[2,seg]			--add up lengths--
		tga	+= t[1,seg]			--add up tangential angles--
		hgt += t[6,seg]			--add up height changes--
		if seg > 1				--need two points to make a segment--
			xCor += t[2,seg-1] / sqrt( pow(m,2) + 1 )						--add up xCordinates at End point of last segment-- --find x length ; formula ref: http://tinyurl.com/h98acjw--
			if t[6,seg] < 0 	--cant calc m with neg num--
				m := (-t[6,seg] / sqrt( abs(pow(t[2,seg],2) - pow(-t[6,seg],2)) ) )	--find slope ΔZ/ΔX on current segment--
				m := m*-1
			else 
				m := (t[6,seg] / sqrt( abs(pow(t[2,seg],2) - pow(t[6,seg],2)) ) )	--find slope ΔZ/ΔX on current segment--
			end
		end
	until len >= ?.sensorID(SensorID).Position	--repeat until accum length is >= Sensor Position--
	tga := tga*(pi/180)			--convert deg to radians--
	--calculations for x,y,z placement--
	if t[6,seg] < 0 	--cant calc m with neg num--
		m := (-t[6,seg] / sqrt( abs(pow(t[2,seg],2) - pow(-t[6,seg],2)) ) )	--find slope ΔZ/ΔX on current segment--
		m := m*-1
	else 
		m := (t[6,seg] / sqrt( abs(pow(t[2,seg],2) - pow(t[6,seg],2)) ) )	--find slope ΔZ/ΔX on current segment--
	end
	senSegPos := ?.sensorID(SensorID).Position-(len-t[2,seg])		--length position of Sensor on it's segment--
	SphrX := senSegPos / sqrt( pow(m,2) + 1 ) 						--reletive x length on segment; formula ref: http://tinyurl.com/h98acjw--
	SphrHgt := (m*SphrX) + t[9,seg-1] // ?._3D.BaseHeight 			--z = mx + b to find Sphere Height--
	SphrX += xCor													--absolute x length--
	--build graphic; set init color--
	?._3D.addGraphicGroup("PRS1_"+SensorID,true, true)
	?._3D.createSphere(makeArray(cos(tga)*SphrX,sin(tga)+0.25,SphrHgt), 0.1, "PRS1_"+SensorID)
	?._3D.setGraphicMaterial(makeArray(1), makeRGBValue(160,160,164), makeRGBValue(0,0,0), makeRGBValue(0,0,0), makeRGBValue(0,0,0), 0.0, 0.2, "PRS1_"+SensorID) 	--white; off
end

?._3D.setGraphicMaterial(makeArray(1), makeRGBValue(160,160,164), makeRGBValue(255,0,0), makeRGBValue(255,0,0), makeRGBValue(255,0,0), 0.0, 0.2, "PRS1_"+SensorID) 	--red; on
wait PRS_Timeout
?._3D.setGraphicMaterial(makeArray(1), makeRGBValue(160,160,164), makeRGBValue(0,0,0), makeRGBValue(0,0,0), makeRGBValue(0,0,0), 0.0, 0.2, "PRS1_"+SensorID) 		--white; off