1.通过w(红色臂角度增大)s(红色臂角度减小)d(蓝色臂角度增大)a(蓝色臂角度减小)按键控制机械臂
注意:关闭计算机的杀毒软件,电脑管家,防火墙
1)基于TCP服务器的机械臂,端口号是8888, ip是Windows的ip;
查看Windows的IP:按住Windows+r 按键,输入cmd , 输入ipconfig
2)点击软件中的开启监听;
3)机械臂需要发送16进制数,共5个字节,协议如下
1、0xff 0x02 x y 0xff
2、0xff:起始结束协议,固定的;
3、0x02:控制机械手臂协议,固定的;
4、x:指定要操作的机械臂
0x00 红色摆臂
0x01 蓝色摆臂
5、y:指定角度
代码:
#include <myhead.h>
#define SER_PORT 8888 //服务器端口号
#define SER_IP "192.168.0.135" //服务器ip地址
#define CLI_PORT 6666 //客户端端口号
#define CLI_IP "192.168.0.101" //客户端ip地址
int main(int argc, char const *argv[])
{
//1. 创建用于通信的套接字文件描述符
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if (cfd == -1)
{
perror("socket error");
return -1;
}
printf("socket success\n");
//将端口号快速重用
int reuse =1;
if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))==-1)
{
perror("stesockopt error");
return -1;
}
printf("端口号快速重用成功\n");
//2.绑定IP地址和端口号
//2.1 填充地址信息结构体
struct sockaddr_in cin;
cin.sin_family = AF_INET; //通信域
cin.sin_port = htons(CLI_PORT); //端口号
cin.sin_addr.s_addr = inet_addr(CLI_IP); //IP地址
//2.2绑定工作
if (bind(cfd, (struct sockaddr *)&cin, sizeof(cin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
//3. 连接服务器
//3.1 填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SER_PORT); //服务器端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //服务器IP地址
//3.2 开始连接
if (connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("connect error");
return -1;
}
printf("连接成功\n");
//准备数据
char rbuf[5] = {0xff, 0x02, 0x00, 0x00, 0xff}; //16进制
char bbuf[5] = {0xff, 0x02, 0x01, 0x5A, 0xff};
//发送给服务器,以初始化机械臂
send(cfd, rbuf, sizeof(rbuf), 0);
sleep(1);
send(cfd, bbuf, sizeof(bbuf), 0);
printf("按q可退出\n");
while (1)
{
char x = getchar();
getchar(); //吸收回车
if (x == 'w')
{
if (rbuf[3] > -90 && rbuf[3] <=85)
{
rbuf[3] = rbuf[3] + 5;
send(cfd, rbuf, sizeof(rbuf), 0);
}
}
else if (x == 's')
{
if (rbuf[3] >= -85 && rbuf[3] < 90)
{
rbuf[3] = rbuf[3] - 5;
send(cfd, rbuf, sizeof(rbuf), 0);
}
}
else if (x == 'a')
{
if (bbuf[3] >= 5 && bbuf[3] < 180)
{
bbuf[3] = bbuf[3] - 5;
send(cfd, bbuf, sizeof(bbuf), 0);
}
}
else if (x == 'd')
{
if (bbuf[3] > -0 && bbuf[3] <= 175)
{
bbuf[3] = bbuf[3] + 5;
send(cfd, bbuf, sizeof(bbuf), 0);
}
}
else if (x == 'q')
{
break;
}
else
{
printf("您输入的命令有误\n");
}
}
//关闭套接字
close(cfd);
return 0;
}
演示图片:
虽然代码可行,但每次操作都要按一次回车,会有点麻烦,本文只提供最基础写法。
新增代码
#include <myhead.h>
#include <linux/input.h>
#define SER_PORT 8888 //服务器端口号
#define SER_IP "192.168.0.135" //服务器ip地址
#define CLI_PORT 6666 //客户端端口号
#define CLI_IP "192.168.0.147" //客户端ip地址
int main(int argc, char const *argv[])
{
//1. 创建用于通信的套接字文件描述符
int cfd = socket(AF_INET, SOCK_STREAM, 0);
if (cfd == -1)
{
perror("socket error");
return -1;
}
printf("socket success\n");
//将端口号快速重用
int reuse = 1;
if (setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
{
perror("stesockopt error");
return -1;
}
printf("端口号快速重用成功\n");
//打开键盘驱动文件
int fd = open("/dev/input/event1", O_RDONLY);
if (fd == -1)
{
perror("open error");
return -1;
}
//定义容器接收数据
struct input_event ie; //关于键盘的文件结构体
//3. 连接服务器
//3.1 填充服务器地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; //通信域
sin.sin_port = htons(SER_PORT); //服务器端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); //服务器IP地址
//3.2 开始连接
if (connect(cfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("connect error");
return -1;
}
printf("连接成功\n");
//准备数据
char rbuf[5] = {0xff, 0x02, 0x00, 0x00, 0xff}; //16进制
unsigned char bbuf[5] = {0xff, 0x02, 0x01, 0x5A, 0xff};
//发送给服务器,以初始化机械臂
send(cfd, rbuf, sizeof(rbuf), 0);
sleep(1);
send(cfd, bbuf, sizeof(bbuf), 0);
while (1)
{
//从驱动文件中读取数据
read(fd, &ie, sizeof(ie));
//对输入的数据进行判断
switch (ie.code * ie.value)
{
case 32: //表示按下了d键
{
if (bbuf[3] > -0 && bbuf[3] <= 175)
{
bbuf[3] = bbuf[3] + 5;
send(cfd, bbuf, sizeof(bbuf), 0);
}
}
break;
case 31: //表示按下了s键
{
if (rbuf[3] >= -85 && rbuf[3] < 90)
{
rbuf[3] = rbuf[3] - 5;
send(cfd, rbuf, sizeof(rbuf), 0);
}
}
break;
case 30: //表示按下了a键
{
if (bbuf[3] >= 5 && bbuf[3] < 180)
{
bbuf[3] = bbuf[3] - 5;
send(cfd, bbuf, sizeof(bbuf), 0);
}
}
break;
case 17: //表示按下了w键
{
if (rbuf[3] > -90 && rbuf[3] <= 85)
{
rbuf[3] = rbuf[3] + 5;
send(cfd, rbuf, sizeof(rbuf), 0);
}
}
break;
}
}
//关闭套接字
close(cfd);
return 0;
}
修改了一下,利用直接读取驱动盘(键盘)文件,可以省略按回车的步骤。
在运行a.out文件时,前面要加上 sudo ,即 sudo ./a.out