1、C++利用UDP socket发送结构体数据
之前也看了一些博客,sendto只能发送char型数据,所以如果要发送非字符型的数据,要先转换一下。
这两条代码强制转化了结构体数据,如果要使用其他类型的数据,变换方式也类似。
camcoord udpPack;
char *pPack = (char *)&udpPack;
Sendto函数原型
int
WSAAPI
sendto(
_In_ SOCKET s,
_In_reads_bytes_(len) const char FAR * buf,
_In_ int len,
_In_ int flags,
_In_reads_bytes_(tolen) const struct sockaddr FAR * to,
_In_ int tolen
);
s:已建好连线的socket, 如果利用UDP协议则不需经过连线操作.
buf: 指向欲连线的数据内容, 这里就是结构体的指针
len:数据的大小,在本例中数组里面的内容是double型的,每一个double分配8个char,所以 len=4*8=32.
一定要根据数据的大小合理设置长度,否则数据会乱。
flags :一般设0
to :用来指定欲传送的网络地址, 结构sockaddr 参考bind().
tolen :为sockaddr 的结果长度.
UDP 发送端的代码转自
https://blog.csdn.net/qq_29422251/article/details/53390587
#include <stdio.h>
#include <string>
#include <iostream>
#include <winsock.h>
using namespace std;
//创建新的套接字之前需要调用一个引入Ws2_32.dll库的函数,否则服务器和客户端连接不上
#pragma comment(lib,"ws2_32.lib")
typedef struct CamCoord {
double a;//the angle of camera turning
double x;
double y;
double z;
}camcoord, *pcam;
WSADATA wsaData; //指向WinSocket信息结构的指针
SOCKET serSocket; //创建套接字
SOCKADDR_IN serUdpServ, clientAddr; //指向通信对象的结构体指针
int main(int argc, char* argv[])
{
camcoord udpPack;
char *pPack = (char *)&udpPack;
//*************************** 第一步初始化Winsock *****************************//
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) //进行WinSocket的初始化
{
printf("Can't initiates windows socket!Program stop.\n");//初始化失败返回-1
return -1;
}
//******************** 第二步建立一个数据报类型的UDP套接字 ******************//
serSocket = socket(PF_INET, SOCK_DGRAM, 0);
serUdpServ.sin_family = AF_INET;
serUdpServ.sin_addr.s_addr = inet_addr("127.0.0.1");
//saUdpServ.sin_addr.s_addr = htonl ( INADDR_BROADCAST );
serUdpServ.sin_port = htons(8001); //发送用的端口,可以根据需要更改
clientAddr.sin_family = AF_INET;
clientAddr.sin_port = htons(4337);
clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (bind(serSocket, (sockaddr *)&serUdpServ, sizeof(serUdpServ)) == SOCKET_ERROR)
{
printf("bind error !");
closesocket(serSocket);
return 0;
}
/*
if (Communicarte() == 0||Communicarte() == -1)
return 0;
*/
udpPack.a = 52.12221;
udpPack.x = 15.23221;
udpPack.y = 65.34221;
udpPack.z = 65.34221;
while (1)
{
Sleep(1000);
//********************** 第三步使用sendto函数进行通信 *************************//
sendto(serSocket, pPack, 32, 0, (struct sockaddr*)&clientAddr, sizeof(clientAddr));
}
//********************* 第四步关闭socket ***************************************//
closesocket(serSocket); //关闭监听socket
WSACleanup();
return 0;
}
2、SImulink框架
3、UDP receive模块参数设置
几个需要注意的地方:
Block sample time是数据的采样时间,这里取0.001和C++中轨迹规划的时间间隔保持一致就可以保证时间同步了,不需要再
real-time sychronization 保证时间让仿真时间与实际同步,反而是这个模块有最大丢包报错功能,如果编译时间慢了错过了接收数据会报错,有点麻烦。
UDP地址配置:
Local address 可以通过查看IPV4地址得到,但是不同的无线网络环境下,IPV4地址总是变化的,可能今天改好的端口,明天就报错了。所以我在做调试的时候用了一个调试助手,可以自动读取本地主机的地址,比较方便。(之前做通信连接的时候也借助了这个工具)【NetAssist网络调试助手】
Byte order:数据发送的时候是大端序还是小端序,如果数据乱码,需要检查一下这里。
4、 Simulink中timeseries类的导入
目前在试过的所有模块中,基本能够确定timeseries只能通过to workspace或者from workspace保存或引用自workspace。
如果想要直接利用simulink中的模块产生timeseries基本不可能,好在UDP导出的数据本身就是timeseries类型的,不然还真不知道怎么弄。
如果需要模拟timeseries那样按照固定的时间步长在simulink仿真过程中传输数据,只能通过设置Fixed-step size和引入counter模块方式实现。【仅有来自MATLAB中文论坛的资料,可能是唯一能够实现的方法】(https://www.ilovematlab.cn/thread-473355-1-1.html)
5、Simscape导入URDF文件开始仿真
https://blog.csdn.net/xiaohejiaoyiya/article/details/104954035