新松机械臂 2001端口服务的客户端例程

news2025/7/23 15:53:12

初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。

源码指引:github源码指引_初级代码游戏的博客-CSDN博客

C#是我多年以来的业余爱好,新搞的东西能用C#的就用C#了。


        新松机械臂报告状态的端口是2001,每100毫秒报告一次状态,每次报告数据长度1468字节。

        这个端口只用来报告状态,控制则使用2000端口。

        获取状态非常简单,连接上去,读取数据,按照格式拆分数据即可。具体数据数据格式见开发手册。

目录

一、C++头文件

二、main函数

三、核心代码

四、运行


 

一、C++头文件

         只需要使用C++头文件DucoRobat.h即可。其实并不需要这个头文件,本例程中引入是因为借用了里面定义好的状态结构而已:

// 机器人相关信息
struct RobotStatusList
{
	std::vector<double>  jointExpectPosition;   // 目标关节位置
	std::vector<double>  jointExpectVelocity;   // 目标角速度
	std::vector<double>  jointExpectAccelera;   // 目标角加速度
	std::vector<double>  jointActualPosition;   // 实际关节位置
	std::vector<double>  jointActualVelocity;   // 实际角速度
	std::vector<double>  jointActualAccelera;   // 实际角加速度
	std::vector<double>  jointActualCurrent;    // 实际关节电流
	std::vector<double>  jointTemperature;      // 时间关节温度
	std::vector<double>  driverTemperature;     // 未使用
	std::vector<double>  cartExpectPosition;    // 目标末端位姿
	std::vector<double>  cartExpectVelocity;    // 目标末端速度
	std::vector<double>  cartExpectAccelera;    // 目标末端加速度
	std::vector<double>  cartActualPosition;    // 实际末端位姿
	std::vector<double>  cartActualVelocity;    // 实际末端速度
	std::vector<double>  cartActualAccelera;    // 实际末端加速度
	std::vector<bool>    slaveReady;            // 从站状态
	bool    collision;       // 是否发生碰撞
	int8_t  collisionAxis;   // 发生碰撞的关节
	bool    emcStopSignal;   // 未使用
	int8_t  robotState;      // 机器人状态
	int32_t robotError;      // 机器人错误码
};

二、main函数

int main(int argc, char** argv)
{
	if (!InitActiveApp("DOUCO", 1024 * 1024 * 10, argc, argv))return 1;
	thelog << "新松机器人 TCP及IP接口" << endi;

	WORD sockVersion = MAKEWORD(1, 1);
	WSADATA wsaData;
	if (WSAStartup(sockVersion, &wsaData) != 0)
	{
		return 0;
	}

	bool bExitCmd = false;
	thread t(CMyDUCO::VirtualServer, &bExitCmd);//模拟服务
	SleepSeconds(1);

	CMyDUCO myduco;
	string ip = "127.0.0.1";//正式使用修改为设备实际IP
	thelog << "连接 " << ip << " ......"<< endi;
	if (!myduco.Recv(ip.c_str()))
	{
		thelog << "连接到 " << ip << " 失败" << ende;
	}
	else
	{
		myduco.ProcessFrame();
		myduco.Print();
		myduco.Save();
	}
	
	while (true)SleepSeconds(5);

	bExitCmd = true;
	t.join();

	WSACleanup();
	return 0;
}

        这个代码默认访问自带的模拟服务,实际使用修改目标IP(代码中已标注)。

三、核心代码

// DUCO.h : 新松机器人 TCP及IP接口
//

#include <iostream>
//#include "DucoCobot.h"
//using namespace DucoRPC;
using namespace std;
#include "env/myUtil.h"
#include "function/htmldoc.h"
#include "function/mysocket.h"
using namespace ns_my_std;

#pragma comment(lib,"ws2_32.lib")
// 机器人相关信息
struct RobotStatusList
{
	std::vector<double>  jointExpectPosition;   // 目标关节位置
	std::vector<double>  jointExpectVelocity;   // 目标角速度
	std::vector<double>  jointExpectAccelera;   // 目标角加速度
	std::vector<double>  jointActualPosition;   // 实际关节位置
	std::vector<double>  jointActualVelocity;   // 实际角速度
	std::vector<double>  jointActualAccelera;   // 实际角加速度
	std::vector<double>  jointActualCurrent;    // 实际关节电流
	std::vector<double>  jointTemperature;      // 时间关节温度
	std::vector<double>  driverTemperature;     // 未使用
	std::vector<double>  cartExpectPosition;    // 目标末端位姿
	std::vector<double>  cartExpectVelocity;    // 目标末端速度
	std::vector<double>  cartExpectAccelera;    // 目标末端加速度
	std::vector<double>  cartActualPosition;    // 实际末端位姿
	std::vector<double>  cartActualVelocity;    // 实际末端速度
	std::vector<double>  cartActualAccelera;    // 实际末端加速度
	std::vector<bool>    slaveReady;            // 从站状态
	bool    collision;       // 是否发生碰撞
	int8_t  collisionAxis;   // 发生碰撞的关节
	bool    emcStopSignal;   // 未使用
	int8_t  robotState;      // 机器人状态
	int32_t robotError;      // 机器人错误码
};

constexpr int frame_size = 1468;
class CMyDUCO
{
private:
	int32_t _getUInt(int byte_pos)
	{
		if (4 != sizeof(int32_t))throw "4 != sizeof(int32_t)";
		int32_t tmp;
		memcpy(&tmp, frame + byte_pos, sizeof(int32_t));
		return tmp;
	}
	float _getFloat(int byte_pos)
	{
		if (4 != sizeof(float))throw "4 != sizeof(float)";
		float tmp;
		memcpy(&tmp, frame + byte_pos, sizeof(float));
		return tmp;
	}
	void _FloatX(vector<double>& vd7, int count, int byte_pos)
	{
		vd7.clear();
		for (int i = 0; i < count; ++i)
		{
			vd7.push_back(_getFloat(byte_pos + i * 4));
		}
	}
	union
	{
		char frame[frame_size];
		float _;
	}m_frame;
	char* frame = m_frame.frame;
	RobotStatusList m_RobotStatusList;
public:
	bool Save()
	{
		CEasyFile file;
		for (int i = 0; i < 100; ++i)
		{
			char buf[256];
			sprintf(buf, "data%03d.dat", i);
			if (file.IsFileExist(buf))continue;
			return file.WriteFile(buf, frame, frame_size);
		}
		thelog << "已经存在的文件太多" << ende;
		return false;
	}
	void ProcessFrame()
	{
		// 目标关节位置
		_FloatX(m_RobotStatusList.jointExpectPosition, 7, 112);
		// 目标角速度
		_FloatX(m_RobotStatusList.jointExpectVelocity, 7, 140);
		// 目标角加速度
		_FloatX(m_RobotStatusList.jointExpectAccelera, 7, 168);

		// 实际关节位置
		_FloatX(m_RobotStatusList.jointActualPosition, 7, 0);
		// 实际角速度
		_FloatX(m_RobotStatusList.jointActualVelocity, 7, 28);
		// 实际角加速度
		_FloatX(m_RobotStatusList.jointActualAccelera, 7, 56);
		// 实际关节电流
		_FloatX(m_RobotStatusList.jointActualCurrent, 7, 252);
		// 实际关节温度
		_FloatX(m_RobotStatusList.jointTemperature, 7, 224);

		// 目标末端位姿
		_FloatX(m_RobotStatusList.cartExpectPosition, 6, 464);
		// 目标末端速度
		_FloatX(m_RobotStatusList.cartExpectVelocity, 6, 488);
		// 目标末端加速度
		_FloatX(m_RobotStatusList.cartExpectAccelera, 6, 512);

		// 实际末端位姿
		_FloatX(m_RobotStatusList.cartActualPosition, 6, 368);
		// 实际末端速度
		_FloatX(m_RobotStatusList.cartActualVelocity, 6, 392);
		// 实际末端加速度
		_FloatX(m_RobotStatusList.cartActualAccelera, 6, 416);

		// 是否发生碰撞
		m_RobotStatusList.collision = (1 == frame[1452]);
		// 发生碰撞的关节
		m_RobotStatusList.collisionAxis = frame[1453];
		// 机器人状态
		m_RobotStatusList.robotState = frame[1449];
		// 机器人错误码
		m_RobotStatusList.robotError = _getUInt(1456);
	}
	void Random()
	{
		static int base = 0;
		float* p = &m_frame._;
		for (int i = 0; i < frame_size / 4; ++i)
		{
			p[i] = base+i;
		}
		++base;

		// 是否发生碰撞
		frame[1452] = 1;
		// 发生碰撞的关节
		frame[1453] = 6;
		// 机器人状态
		frame[1449] = 9;
		// 机器人错误码
		*(int32_t*)&frame[1456] = 10;
	}
	void _PrintV(CHtmlDoc::CHtmlTable2 &table,vector<double> & vectorD, char const* title)
	{
		table.AddLine();
		table.AddData(title);
		for (auto v : vectorD)
		{
			table.AddData(v, 2);
		}
	}
	void Print()
	{
		CHtmlDoc::CHtmlTable2 table;
		table.AddCol("名称");
		for (int i = 0; i < 7; ++i)
		{
			char buf[32];
			sprintf(buf, "关节%d", i + 1);
			table.AddCol(buf, CHtmlDoc::CHtmlDoc_DATACLASS_RIGHT);
		}

		_PrintV(table, m_RobotStatusList.jointExpectPosition, "目标关节位置");
		_PrintV(table, m_RobotStatusList.jointExpectVelocity, "目标角速度");
		_PrintV(table, m_RobotStatusList.jointExpectAccelera, "目标角加速度");
		_PrintV(table, m_RobotStatusList.jointActualPosition, "实际关节位置");
		_PrintV(table, m_RobotStatusList.jointActualVelocity, "实际角速度");
		_PrintV(table, m_RobotStatusList.jointActualAccelera, "实际角加速度");
		_PrintV(table, m_RobotStatusList.jointActualCurrent, "实际关节电流");
		_PrintV(table, m_RobotStatusList.jointTemperature, "时间关节温度");
		_PrintV(table, m_RobotStatusList.driverTemperature, "未使用");
		_PrintV(table, m_RobotStatusList.cartExpectPosition, "目标末端位姿");
		_PrintV(table, m_RobotStatusList.cartExpectVelocity, "目标末端速度");
		_PrintV(table, m_RobotStatusList.cartExpectAccelera, "目标末端加速度");
		_PrintV(table, m_RobotStatusList.cartActualPosition, "实际末端位姿");
		_PrintV(table, m_RobotStatusList.cartActualVelocity, "实际末端速度");
		_PrintV(table, m_RobotStatusList.cartActualAccelera, "实际末端加速度");
		theLog << table.MakeTextTable() << endi;
		theLog << endl << m_RobotStatusList.collision << " 是否发生碰撞" << endl;
		theLog << (int)m_RobotStatusList.collisionAxis << " 发生碰撞的关节" << endl;
		theLog << (int)m_RobotStatusList.robotState << " 机器人状态" << endl;
		theLog << m_RobotStatusList.robotError << " 机器人错误码" << endi;
	}
	//接收数据
	bool Recv(char const * ip)
	{
		CMySocket s;
		if (!s.Connect(ip, 2001))
		{
			thelog << "连接失败 "<<ip << ende;
			return false;
		}
		thelog << "连接成功 " << ip << endi;

		int count = 0;
		while (count != frame_size)
		{
			long readCount = 0;
			if (!s.Recv(frame + count, frame_size - count, &readCount))
			{
				thelog << "接收失败 " << ip << ende;
				s.Close();
				return false;
			}
			thelog << readCount<<" 收到数据 " << count << endi;
			count += readCount;
		}
	
		thelog << "收到数据 " << count << endi;
		s.Close();
		return count == frame_size;
	}
	//虚拟服务
	static void VirtualServer(bool * pExitCmd)
	{
		thelog.SetSource("TEST SERVER");

		CMySocket s;
		if (!s.Listen(2001))
		{
			thelog << "监听端口2001失败" << ende;
			exit(1);
		}
		thelog << "服务已创建" << endi;
		while (!*pExitCmd)
		{
			bool tmp_bool;
			if (!s.IsSocketReadReady(1, tmp_bool))
			{
				thelog << "IsSocketReadReady失败" << ende;
				exit(1);
			}
			if (!tmp_bool)continue;

			CMySocket client_socket = s.Accept();
			if (!client_socket.IsConnected())
			{
				thelog << "Accept失败" << ende;
				exit(1);
			}
			thelog << "Accept成功" << endi;
			CMyDUCO myDUCO;
			myDUCO.Random();
			client_socket.Send(myDUCO.frame, frame_size);
			client_socket.Close();
		}
		s.Close();
		thelog << "服务结束" << endi;
	}
};

        这个代码已经把所需的结构直接放进来了,不需要包含DucoRobat.h。

        代码主要功能:

  • Save 保存到当前目录
  • ProcessFrame 解析收到的数据
  • Random 用于模拟服务生成数据,其实并不是随机,而是递增
  • Print 输出表格
  • Recv 接收数据
  • VirtualServer 内置模拟服务

四、运行

        运行起来结果如下:

[05-30 11:13:55][应用][信息][C:\working\IoT\DUCO\main_t.cpp:  12(main)][  0.00]新松机器人 TCP及IP接口
[05-30 11:13:55][TEST SERVER][12824- 1][信息][C:\working\IoT\DUCO\myDUCO.h: 230(VirtualServer)][  0.02]服务已创建
[05-30 11:13:56][应用][12824][信息][C:\working\IoT\DUCO\main_t.cpp:  27(main)][  1.01]连接 127.0.0.1 ......
[05-30 11:13:56][应用][12824][信息][C:\working\IoT\DUCO\myDUCO.h: 199(Recv)][  1.01]连接成功 127.0.0.1
[05-30 11:13:56][TEST SERVER][12824- 1][信息][C:\working\IoT\DUCO\myDUCO.h: 247(VirtualServer)][  1.01]Accept成功
[05-30 11:13:56][应用][12824][信息][C:\working\IoT\DUCO\myDUCO.h: 211(Recv)][  1.01]1468 收到数据 0
[05-30 11:13:56][应用][12824][信息][C:\working\IoT\DUCO\myDUCO.h: 215(Recv)][  1.01]收到数据 1468
[05-30 11:13:56][应用][12824][信息]
名称            关节1  关节2  关节3  关节4  关节5  关节6 关节7
-------------- ------ ------ ------ ------ ------ ------ -----
目标关节位置    28.00  29.00  30.00  31.00  32.00  33.00 34.00
目标角速度      35.00  36.00  37.00  38.00  39.00  40.00 41.00
目标角加速度    42.00  43.00  44.00  45.00  46.00  47.00 48.00
实际关节位置     0.00   1.00   2.00   3.00   4.00   5.00  6.00
实际角速度       7.00   8.00   9.00  10.00  11.00  12.00 13.00
实际角加速度    14.00  15.00  16.00  17.00  18.00  19.00 20.00
实际关节电流    63.00  64.00  65.00  66.00  67.00  68.00 69.00
时间关节温度    56.00  57.00  58.00  59.00  60.00  61.00 62.00
未使用
目标末端位姿   116.00 117.00 118.00 119.00 120.00 121.00
目标末端速度   122.00 123.00 124.00 125.00 126.00 127.00
目标末端加速度 128.00 129.00 130.00 131.00 132.00 133.00
实际末端位姿    92.00  93.00  94.00  95.00  96.00  97.00
实际末端速度    98.00  99.00 100.00 101.00 102.00 103.00
实际末端加速度 104.00 105.00 106.00 107.00 108.00 109.00
-------------- ------ ------ ------ ------ ------ ------ -----


[05-30 11:13:56][应用][12824][信息]
1 是否发生碰撞
6 发生碰撞的关节
9 机器人状态
10 机器人错误码

        其实相当简单。


(这里是文档结束)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2400695.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电脑网络重置,找不到原先自家的WIFI,手机还能正常连接并上网

问题排查&#xff1a;1、电脑感觉网络太慢&#xff0c;因此打算点击了网络重置 2、点击提示会删除网络&#xff0c;在五分钟后关机重启 3、从设备管理器设备的无线wifi属性-事件中发现删除记录 4、选择更新驱动程序 5、从列表中选取 6、更改回老驱动版本 备选方案&#…

期末复习(学习)之机器学习入门基础

上课没听过报道。欢迎补充交流&#xff01; 前言&#xff1a;老师画的重点其实可以完全不用看&#xff0c;我这里只是看了一眼书顺着书本敲一遍。 比较干货的部分&#xff0c;直接看学习通的内容就好。最重要的是把学习通的内容记好。 目录 老师划的重点&#xff1a;P50 结构…

网络各类型(BMA,NBMA,P2P)

网络类型—基于二层&#xff08;数据链路层&#xff09;使用的协议不同从而导致数据包封装方式不同&#xff0c;工作方式也有所区别&#xff0c;从而对网络本身进行分类 一、网络类型分类 2. 关键差异对比 1. HDLC&#xff08;高级数据链路控制协议&#xff09; 协议特点&…

【计算机网络】第3章:传输层—概述、多路复用与解复用、UDP

目录 一、概述和传输层服务 二、多路复用与解复用 三、无连接传输&#xff1a;UDP 四、总结 &#xff08;一&#xff09;多路复用与解复用 &#xff08;二&#xff09;UDP 一、概述和传输层服务 二、多路复用与解复用 三、无连接传输&#xff1a;UDP 四、总结 &#xff08…

神经符号AI的企业应用:结合符号推理与深度学习的混合智能

&#x1f4a1; 技术前沿&#xff1a; 神经符号AI代表了人工智能发展的新阶段&#xff0c;它将深度学习的模式识别能力与符号推理的逻辑分析能力有机结合&#xff0c;创造出更加智能、可解释且可靠的AI系统。这种混合智能技术正在重塑企业的智能化应用&#xff0c;从自动化决策到…

VSCode 中 C/C++ 安装、配置、使用全攻略:小白入门指南

引言 本文为Windows系统下安装配置与使用VSCode编写C/C代码的完整攻略&#xff0c;示例机器为Windows11。 通过本文的指导&#xff0c;你可以成功在Windows 机器上上使用VSCode进行C/C开发。 在文章开始之前&#xff0c;你可以先阅读下面这段话&#xff0c;以便于对步骤有个大…

重温经典算法——希尔排序

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 基本原理 希尔排序是插入排序的改进版&#xff0c;通过按增量分组并逐步缩小增量实现排序。时间复杂度取决于增量序列&#xff0c;平均约为 O(n log n) 到 O(n^(3/2))&…

CortexON:开源的多代理AI系统无缝自动化和简化日常任务

简介 CortexON是一个开源的多代理AI系统&#xff0c;灵感来自Manus和OpenAI DeepResearch等高级代理平台。CortexON旨在无缝自动化和简化日常任务&#xff0c;擅长执行复杂的工作流程&#xff0c;包括全面的研究任务、技术操作和复杂的业务流程自动化。 技术架构 CortexON的技…

海信IP810N-海思MV320芯片-安卓9-2+16G-免拆优盘卡刷固件包

海信IP810N-海思MV320芯片-安卓9-216G-免拆优盘卡刷固件包 线刷方法&#xff1a;&#xff08;新手参考借鉴一下&#xff09; 1.准备一个优盘&#xff0c;最佳是4G&#xff0c;卡刷强刷刷机&#xff0c;用一个usb2.0的8G以下U盘&#xff0c;fat32&#xff0c;2048块单分区格式化…

2025年6月4日收获

Authorization Authorization是一种通用的、标准化的权限控制和认证的通用框架&#xff0c;它能够使跨系统和跨域的身份验证和授权管理更容易&#xff0c;使不同应用程序之间能够更轻松地实现单点登录&#xff08;SSO&#xff09;、用户身份验证和授权控制等。 在前端使用 axi…

leetcode hot100 链表(二)

书接上回&#xff1a; leetcode hot100 链表&#xff08;一&#xff09;-CSDN博客 8.删除链表的倒数第N个结点 class Solution { public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* currhead;int len0;while(curr){currcurr->next;len;}int poslen-n…

6. MySQL基本查询

1. 表的增删改查 Create(创建), Retrieve(读取), Update(更新), Delete(删除) 2. Create & Insert 语法: insert [info] table_name () values () 2.1. 案例: 创建一个学生表 指定列单行插入, 如果values前省略, 则默认是全属性插入多行指定列插入, 中间分隔符为, 3. 插入替…

CMS32M65xx/67xx系列CoreMark跑分测试

CMS32M65xx/67xx系列CoreMark跑分测试 1、参考资料准备 1.1、STM32官方跑分链接 1.2、官网链接 官方移植文档&#xff0c;如下所示&#xff0c;点击红框处-移植文档: A new whitepaper and video explain how to port CoreMark-Pro to bare-metal 1.3、测试软件git下载链接 …

中国区域30m/15天植被覆盖度数据集(2010-2022)

时间分辨率&#xff1a;日空间分辨率&#xff1b;&#xff1a;10m - 100m共享方&#xff1a;式开放获取数据大小&#xff1a;2.98 TB数据时间范围&#xff1a;2010-01-01 — 2022-12-31元数据更新时间&#xff1a;2024-12-23 数据集摘要 高时空分辨率的植被覆盖度产品存在着广…

力扣HOT100之二分查找:74. 搜索二维矩阵

这道题直接a了&#xff0c;我们可以参考上一道题&#xff1a;35.搜索插入位置的思路&#xff0c;详情见我的上一篇博客。将每一行的第一个元素当作一个数组中的元素&#xff0c;然后对这个数组进行二分查找&#xff0c;如果直接找到了target&#xff0c;则直接返回true&#xf…

编程技能:格式化打印04,sprintf

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;编程技能&#xff1a;格式化打印03&#xff0c;printf 回到目录…

R语言基础| 下载、安装

在此前的单细胞教程中&#xff0c;许多小伙伴都曾因为R语言基础不足而十分苦恼。R语言是一种开源的编程语言和软件环境&#xff0c;专门用于统计分析、图形表示和数据挖掘。它最初由Ross Ihaka和Robert Gentleman在1993年创建&#xff0c;旨在为统计学家和数据分析师提供一个广…

微软的新系统Windows12未来有哪些新特性

在今年即将到来的重大设计升级中,苹果计划对其全线操作系统统一按年份命名,作为另一巨头微软的win12还远吗?win11和win10是微软现在正在用的主流版本,win11系统发布于2021年6月24日,win10系统发布于2015年7月29日。预计win12尝鲜版可能在2025年下半年或明年。 尽管win12还…

在虚拟宇宙中低语——进程间通信,Linux命名管道的前世今生

文章目录 &#x1f30c; 序章&#x1f320; 一、命名管道的宿命与哲学1.1、创建及简单使用1.2、命名管道的工作原理1.3、命名管道与匿名管道的区别 2、命名管道的特点及特殊场景2.1、特点2.2、四种特殊场景 3、命名管道实操3.1、实现文件拷贝3.2、实现进程控制 小结 &#x1f3…

STM32的ADC简介

一、ADC简介 STM32的ADC是一种12位逐次逼近型模拟数字转换器。它具备18个通道&#xff0c;能够测量16个外部信号源以及2个内部信号源。各通道的A/D转换可以执行单次、连续、扫描或间断模式。转换结果可采用左对齐或右对齐的方式&#xff08;12位&#xff09;存储于16位数据寄存…