- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
制作了一个与 python 脚本通信的 Hololens 应用程序。 python脚本将PLC(西门子S7-1200)变量以JSON的形式发送到hololens。 C# 脚本处理 JSON。当脚本从 plc 读取数据时,还可以使用 C# 脚本内的 sendMessage 方法来控制变量。我制作了一个单独的Python脚本来控制PLC,这个我不会分享。
我的 Unity3d C# 脚本:
using UnityEngine;
using System;
using System.IO;
using System.Text;
using System.Linq;
using HoloToolkit.Unity;
using System.Collections.Generic;
using UnityEngine.UI;
using Newtonsoft.Json;
#if !UNITY_EDITOR
using Windows.Networking.Sockets;
using Windows.Networking.Connectivity;
using Windows.Networking;
#endif
#if !UNITY_EDITOR
public class RootObject
{
public int Index { get; set; }
public bool Moto { get; set; }
public bool Start { get; set; }
public bool StartWINCC { get; set; }
public bool Stop { get; set; }
public bool StopWINCC { get; set; }
public bool Tag1 { get; set; }
public bool Tag2 { get; set; }
}
#endif
public class UDPCommunication : Singleton<UDPCommunication>
{
// Connection variables
public string port = "8000";
public string externalIP = "172.16.24.136";
public string externalPort = "8000";
// UI/Text elements
public Text testert;
public Image moto;
public Image start;
public Image startwincc;
public Image stop;
public Image stopwincc;
public Image tag1;
public Image tag2;
public String uitext;
// Sets up a Queue
public readonly static Queue<Action> ExecuteOnMainThread = new Queue<Action>();
#if !UNITY_EDITOR
// Socket initialization
DatagramSocket socket;
#endif
#if !UNITY_EDITOR
// use this for initialization
async void Start()
{
Debug.Log("Waiting for a connection...");
socket = new DatagramSocket();
socket.MessageReceived += Socket_MessageReceived;
HostName IP = null;
try
{
var icp = NetworkInformation.GetInternetConnectionProfile();
IP = Windows.Networking.Connectivity.NetworkInformation.GetHostNames()
.SingleOrDefault(
hn =>
hn.IPInformation?.NetworkAdapter != null && hn.IPInformation.NetworkAdapter.NetworkAdapterId
== icp.NetworkAdapter.NetworkAdapterId);
await socket.BindEndpointAsync(IP, port);
}
catch (Exception e)
{
Debug.Log(e.ToString());
Debug.Log(SocketError.GetStatus(e.HResult).ToString());
return;
}
var message = "hello from " + IP;
await SendMessage(message);
await SendMessage("hello");
Debug.Log("exit start");
}
private async System.Threading.Tasks.Task SendMessage(string message)
{
using (var stream = await socket.GetOutputStreamAsync(new Windows.Networking.HostName(externalIP), externalPort))
{
using (var writer = new Windows.Storage.Streams.DataWriter(stream))
{
var data = Encoding.UTF8.GetBytes(message);
writer.WriteBytes(data);
await writer.StoreAsync();
Debug.Log("Sent: " + message);
}
}
}
#else
// Use this for initialization.
void Start()
{
}
#endif
// Update is called once per frame.
void Update()
{
// Dequeues items until there are no more items on the queue.
while (ExecuteOnMainThread.Count > 0)
{
ExecuteOnMainThread.Dequeue().Invoke();
}
}
#if !UNITY_EDITOR
// this method is purely for setting the UI elements based on the received JSON string.
private void setStuff(string input){
// Turns the json string into an object
var results = JsonConvert.DeserializeObject<RootObject>(input);
// Sets the UI element(and converts it to string, because it is an int)
testert.text = results.Index.ToString();
// sets the image green if the variable is true, and red if it's not
if (results.Moto == true)
{
moto.GetComponent<Image>().color = Color.green;
}
else
{
moto.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.Start == true)
{
start.GetComponent<Image>().color = Color.green;
}
else
{
start.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.StartWINCC == true)
{
startwincc.GetComponent<Image>().color = Color.green;
}
else
{
startwincc.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.Stop == true)
{
stop.GetComponent<Image>().color = Color.green;
}
else
{
stop.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.StopWINCC == true)
{
stopwincc.GetComponent<Image>().color = Color.green;
}
else
{
stopwincc.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.Tag1 == true)
{
tag1.GetComponent<Image>().color = Color.green;
}
else
{
tag1.GetComponent<Image>().color = Color.red;
}
// sets the image green if the variable is true, and red if it's not
if (results.Tag2 == true)
{
tag2.GetComponent<Image>().color = Color.green;
}
else
{
tag2.GetComponent<Image>().color = Color.red;
}
}
//this method gets called when a message is received
private async void Socket_MessageReceived(Windows.Networking.Sockets.DatagramSocket sender, Windows.Networking.Sockets.DatagramSocketMessageReceivedEventArgs args)
{
// Read the received message.
Stream streamIn = args.GetDataStream().AsStreamForRead();
StreamReader reader = new StreamReader(streamIn);
string message = await reader.ReadLineAsync();
Debug.Log("MESSAGE: " + message);
// if the count is zero, the message will be relayed to the setStuff method, which processes the string continuously.
// The message contains a JSON string which is received from the server.
if (ExecuteOnMainThread.Count == 0)
{
ExecuteOnMainThread.Enqueue(() =>
{
setStuff(message);
});
}
}
#endif
}
这是我的 python 服务器代码:
import socket,time
from read import CustOPCLib
class BroadcastServer(object):
def __init__(self,host,port):
self._host = host
self._port = port
self.sock = None
def connect(self):
self.sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
self.sock.connect((self._host,self._port))
def sendMsg(self,msg):
self.sock.send(msg.encode('utf8'))
def disconnect(self):
self.sock.close()
if __name__ == '__main__':
c = CustOPCLib()
c.connect()
Host = '172.16.24.174'
Port = 8000
ser = BroadcastServer(Host,Port)
ser.connect()
msg = 'test'
i = 0
while True:
i = i + 1
msg += (str(i))
ser.sendMsg(c.opcjson())
time.sleep(0.25)
ser.disconnect()
这是读取脚本(p.opcjson() 中的脚本):
from opcua import ua, Client
import json
'''This class makes connection to the OPC-UA server, and has functions that can be used to return the current values of a specific
variable'''
class ReadVariables(object):
'''init function, contains the node locations of the OPC-UA server'''
def __init__(self):
self.jsonobj = {}
self.Index = "ns=7;s=S7-1200 station_2.PLC_OPC_HOLOLENS.DATA.Index"
self.Moto = "ns=7;s=S7-1200 station_2.PLC_OPC_HOLOLENS.MOTO"
self.Start = "ns=7;s=S7-1200 station_2.PLC_OPC_HOLOLENS.START"
self.StartWincc = "ns=7;s=S7-1200 station_2.PLC_OPC_HOLOLENS.STARTWINCC"
self.Stop = "ns=7;s=S7-1200 station_2.PLC_OPC_HOLOLENS.STOP"
self.StopWINCC = "ns=7;s=S7-1200 station_2.PLC_OPC_HOLOLENS.STOPWINCC"
self.Tag_1 = "ns=7;s=S7-1200 station_2.PLC_OPC_HOLOLENS.Tag_1"
self.Tag_2 = "ns=7;s=S7-1200 station_2.PLC_OPC_HOLOLENS.Tag_2"
self.client = None
'''This function connects to the OPC-UA server'''
def connect(self):
print("Connecting to OPC-UA server")
self.client = Client("opc.tcp://Wilrik-PC:4845")
self.client.connect()
print("Connected to OPC-UA server")
'''This function can be used to disconnect from the OPC-UA server'''
def disconnect(self):
print("Disconnecting from OPC-UA server")
self.client.disconnect()
'''This function returns the root node on the OPC-server'''
def get_root_node(self):
root = self.client.get_root_node()
print("Root node is:", root)
return root
'''This function returns the objects node on the OPC-server'''
def get_objects_node(self):
objects = self.client.get_objects_node()
print("Objects node is: ",objects)
return objects
'''This function returns the children of the objects node on the OPC-server'''
def get_objects_node_children(self):
objects = self.client.get_objects_node()
print("children of objects node is:",objects.get_children())
################################################# VARIABLES ###########################################################
'''This function returns the value of the index variable on the OPC-server'''
def index(self):
index = self.client.get_node(self.Index)
return index.get_value()
'''This function returns the value of the moto variable on the OPC-server'''
def moto(self):
moto = self.client.get_node(self.Moto)
return moto.get_value()
'''This function returns the value of the start variable on the OPC-server'''
def start(self):
start = self.client.get_node(self.Start)
return start.get_value()
'''This function returns the value of the startwincc variable on the OPC-server'''
def startwincc(self):
startwincc = self.client.get_node(self.StartWincc)
return startwincc.get_value()
'''This function returns the value of the stop variable on the OPC-server'''
def stop(self):
stop = self.client.get_node(self.Stop)
return stop.get_value()
'''This function returns the value of the stopwincc variable on the OPC-server'''
def stopwincc(self):
stopwincc = self.client.get_node(self.StopWINCC)
return stopwincc.get_value()
'''This function returns the value of the Tag_1 variable on the OPC-server'''
def tag_1(self):
tag1 = self.client.get_node(self.Tag_1)
return tag1.get_value()
'''This function returns the value of the Tag_2 variable on the OPC-server'''
def tag_2(self):
tag2 = self.client.get_node(self.Tag_2)
return tag2.get_value()
################################################# VARIABLES ###########################################################
################################################# JSON ################################################################
def opcjson(self):
self.jsonobj['Index'] = self.index()
self.jsonobj['Moto'] = self.moto()
self.jsonobj['Start'] = self.start()
self.jsonobj['StartWINCC'] = self.startwincc()
self.jsonobj['Stop'] = self.stop()
self.jsonobj['StopWINCC'] = self.stopwincc()
self.jsonobj['Tag1'] = self.tag_1()
self.jsonobj['Tag2'] = self.tag_2()
obj = json.dumps(self.jsonobj)
return self.jsonobj
################################################# JSON ################################################################
更新1:应用了DoctorPangloss的建议,虽然我让它工作了,但它仍然没有按照我想要的方式工作。我目前的情况:我启动我的Unity3d应用程序,然后启动我的python应用程序,unity接收数据,我关闭python脚本并重新启动它,我只接收一次数据,然后挂起。
更新2:删除了这个问题,将其留给那些可以使用它的人。这不包括控制脚本,您必须自己制作。
最佳答案
您的问题与此行有关:
Debug.Log("client message received as: " + clientMessage);
您无法从另一个线程(即您的监听线程)访问 Unity 线程(即 Unity 对象)。将接收到的包入队放入 ConcurrentQueue 队列
,并从 queue
出队,直到 Update
函数内的每个帧都为空。
您的第二个问题与您的 ConcurrentQueue
实现有关。这是不对的。您找到它的地方有这样的评论:
This is not ConcurrentQueue.. but just queue + lock
https://gist.github.com/jaredjenkins/5421892
尝试采用真正的并发队列实现,如下所示: https://github.com/mono/mono/blob/master/mcs/class/referencesource/mscorlib/system/collections/Concurrent/ConcurrentQueue.cs 。使用 TryDequeue(out item)
实际出队,而不是 peek 或 Dequeue
。
您的第三个问题与这些行有关:
using (NetworkStream stream = connectedTcpClient.GetStream())
{
int length;
// Read incomming stream into byte arrary.
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
TCP 不是消息传递协议(protocol)。如果您想发送消息,请使用网络套接字,或者为要从一个地方发送到另一个地方的内容的长度添加长度前缀,即使它只是字符串。这不一定会立即困扰您,但稍后会。
您的第四个问题与p.opcjson()
有关。也许读一次,然后将其保存到变量中?第二次调用时可能会出乎意料地阻塞;我不确定这里发生了什么。
总的来说,我认为您的 C# 监听代码和 Python 代码可能都存在问题。不幸的是,编写自己的 TCP 套接字代码非常容易出错。考虑使用 Asset Store 和 Python 中的 Web 套接字,其语义明显更加直观。
关于c# - unity3d 中的套接字出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49757032/
我使用下拉菜单提供一些不同的链接,但我希望这些链接在同一选项卡中打开,而不是在新选项卡中打开。这是我找到的代码,但我对 Javascript 非常缺乏知识 var urlmenu = docume
我对 javascript 不太了解。但我需要一个垂直菜单上的下拉菜单,它是纯 JavaScript,所以我从 W3 复制/粘贴脚本:https://www.w3schools.com/howto/t
我已经坐了 4 个小时,试图让我的导航显示下 zipper 接垂直,但它继续水平显示它们。我无法弄清楚为什么会发生这种情况或如何解决它。 如果有人能告诉我我做错了什么,我将不胜感激。我有一个潜移默化的
我正在尝试创建选项卡式 Accordion 样式下拉菜单。我使用 jQuery 有一段时间了,但无法使事件状态达到 100%。 我很确定这是我搞砸的 JS。 $('.service-button').
对于那些从未访问过 Dropbox 的人,这里是链接 https://www.dropbox.com/ 查看“登录”的下拉菜单链接。我如何创建这样的下 zipper 接? 最佳答案 这是 fiddle
我正在制作一个 Liferay 主题,但我在尝试设计导航菜单的样式时遇到了很多麻烦。我已经为那些没有像这样下拉的人改变了导航链接上的经典主题悬停功能: .aui #navigation .nav li
如果您将鼠标悬停在 li 上,则会出现一个下拉菜单。如果您将指针向下移至悬停时出现的 ul,我希望链接仍然带有下划线,直到您将箭头从 ul 或链接移开。这样你就知道当菜单下拉时你悬停在哪个菜单上。 知
我有一个带有多个下拉菜单的导航栏。因此,当我单击第一个链接时,它会打开下拉菜单,但是当我单击第二个链接时,第一个下拉菜单不会关闭。 (所以如果用户点击第二个链接我想关闭下拉菜单) // main.js
我正在尝试制作一个导航下拉菜单(使用 Bootstrap 3),其中链接文本在同一行上有多个不同的对齐方式。 在下面的代码中,下拉列表 A 中的链接在 HTML 中有空格字符来对齐它们,但是空白被忽略
我希望有人能帮我解决这个 Bootstrap 问题,因为我很困惑。 有人要求我在底部垂直对齐图像和其中包含图像的链接。 我面临的问题是他们还希望链接在链接/图像组合上具有 pull-right,这会杀
我正在构建一个 Rails 应用程序,并希望指向我的类的每个实例的“显示”页面的链接显示在“索引”页面的下拉列表中。我目前正在使用带有 options_from_collection_for_sele
我有以下 Bootstrap3 导航菜单 ( fiddle here )。我想设置“突出显示”项及其子链接与下拉列表 1 和 2 链接不同的链接文本(和悬停)的样式。我还希望能够以不同于 Highli
我对导航栏中的下拉菜单有疑问。对于普通的导航链接(无下拉菜单),我将菜单文本放在 H3 中,但是当我尝试对下 zipper 接执行相同操作时,箭头不在标题旁边,而是在标题下方。我决定用 span 替换
我是一名优秀的程序员,十分优秀!