如何实现rviz中的机械臂和实际的机械臂同步----ROS机械臂学习笔记(三)

本文介绍了一种通过网络通信使ROS仿真机械臂与实际机械臂实现同步运动的方法。利用Socket编程技术,下位机(实际机械臂所在电脑)将关节角度数据发送至上位机(Ubuntu系统电脑),上位机通过编写ROS节点处理这些数据并发布到JointStates话题,从而更新rviz中机械臂的状态。此外,还探讨了另一种方法,即由上位机规划路径点下发至下位机执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用网络和Joint States话题消息,实现仿真机械臂和实际的机械臂实现同步运动。
下位机:把和实际机械臂相连的电脑称为下位机。
上位机:装有ubuntu的电脑称为上位机。
在一篇的博客中利用joint_states发布消息,去控制机械臂, 我们利用joint states话题去发布关节状态的消息,然后rviz中的机械臂接受到相应的消息之后就会运动。现在我们在下位机中用Socket写一个通信程序,把读取到的实际机械臂的关节角度消息发送给上位机中,然后在上位机中写一个节点,用来接受消息,并且把消息填充到joint states中,最后发布出去。这样就可以实现rviz中的机械臂和实际的机械臂实现同步运动了。
上位机中的节点程序如下:

// receive the news of real joint angle form the TCP/IP,and use the topic JointState to publishe the news.

#include <unistd.h>
#include <stdio.h>
#include<iostream>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <ros/ros.h>
#include <sensor_msgs/JointState.h>

#define SERVER_PORT 17999
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 10

double b=1;

int main(int argc, char* argv[]) // (int argc, char* argv[])
{

    ros::init(argc, argv, "send_denso_date");
    ros::NodeHandle n;
    ros::Rate loop_rate(1000); //下位机中的发送频率是1000HZ ,不相同的话,不能实现同步。
    ros::Publisher joint_pub = n.advertise<sensor_msgs::JointState>("joint_states", 1000);    //设置一个发布者,将消息发布出去,发布到相应的节点中去
    sensor_msgs::JointState joint_state;


    //网络设置部分
    struct sockaddr_in server_addr;
    int server_socket;
    int opt = 1;
     double a=90;
    bzero(&server_addr, sizeof(server_addr)); // 置字节字符串前n个字节为0,包括'\0'
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htons(INADDR_ANY); // 转小端,INADDR_ANY就是指定地址为0.0.0.0的地址
    server_addr.sin_port = htons(SERVER_PORT);  

    // 创建一个Socket
    server_socket = socket(PF_INET, SOCK_STREAM, 0);

    if (server_socket < 0)
    {
        printf("Create Socket Failed!\n");
        exit(1);
    }


    // bind a socket
    setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if(bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)))
    {
        printf("Server Bind Port: %d Failed!\n", SERVER_PORT);
        exit(1);
    }

    // 监听Socket
    if (listen(server_socket, LENGTH_OF_LISTEN_QUEUE))
    {
        printf("Server Listen Failed!\n");
        exit(1);
    }      

    while(1)
    {

        struct sockaddr_in client_addr;
        int client_socket;
        socklen_t length;
        double Buffer[6];

        // 连接客户端Socket
        length = sizeof(client_addr);
        client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &length);
        if (client_socket < 0)
        {
            printf("Server Accept Failed!\n");
            break;
        }
         // 从客户端接收数据
        while(1)
        {
            bzero(Buffer, BUFFER_SIZE);
            length = recv(client_socket, (char*)&Buffer, sizeof(Buffer), 0);      //接受数据

            joint_state.header.stamp = ros::Time::now();                          //创建相应的消息
            joint_state.name.resize(6);
            joint_state.position.resize(6);
          //joint_state.name={"joint1","joint2""joint3""joint4""joint5""joint6"}; //不知道这个为什么不可以。
        joint_state.name[0]="joint1";
            joint_state.position[0] = Buffer[0];
        joint_state.name[1] ="joint2";
            joint_state.position[1] = Buffer[1];
        joint_state.name[2] ="joint3";
            joint_state.position[2] = Buffer[2];
            joint_state.name[3] ="joint4";
            joint_state.position[3] = Buffer[3];
        joint_state.name[4] ="joint5";
            joint_state.position[4] = Buffer[4];
        joint_state.name[5] ="joint6";
            joint_state.position[5] =Buffer[5];
            joint_pub.publish(joint_state);

            loop_rate.sleep();
            send(client_socket, (char*)&b, sizeof(b), 0); 


            if (length < 0)
            {
                printf("Server Recieve Data Failed!\n");
                break;
            }           

            if ('q' == Buffer[0])
            {
                printf("Quit!\n");
                break;
            }

            //printf("%s\n", Buffer);
            std::cout<<Buffer[0]<<std::endl;  //读取数据,只有一个数据
            break;

        }

        close(client_socket);
    }

    close(server_socket);
    return 0;
}

在这种方法中,所有的控制和路径点都是在下位机中实现的和给定的。有一些需要注意的地方就是两者的发送和接受的频率要一致,如果不一致的话,rviz中的模型就会有一种幻影,不能实现同步。

还有一种方法是把moveit中运动规划的轨迹点下发给下位机,下位机接受到相应的轨迹点后进行运动。剩下的依然是在下位机中用Socket写一个通信程序,把读取到的实际机械臂的关节角度消息发送给上位机中,然后在上位机中写一个节点,用来接受消息,并且把消息填充到joint states中,最后发布出去。这样就可以实现rviz中的机械臂和实际的机械臂实现同步运动了。**
在第二种方法中,控制是在下位机中实现的,但是路径点是在上位机中给定的。这种方法目前还在尝试中。

<think>好的,我现在要解决用户在Keil编译过程中遇到的core_cm3.c文件报错问题。根据用户提供的引用信息,我需要先理解问题的原因可能的解决方。 首先,用户提到引用[2]中的信息,指出问题通常是因为使用了新版本的编译器(如Compiler v6)而core_cm3.c文件较旧,导致不兼容。解决方包括替换文件或切换到旧版编译器。引用[1]提到替换core_cm3.h并添加其他头文件,而引用[3]则建议直接删除报错代码,但可能有风险。引用[4]提到NVIC_SystemReset相关的警告,可能与头文件有关。 接下来,我需要将这些信息整理成步骤清晰的解决方案。用户需要明确的步骤,比如替换文件的具体操作,如何获取最新的CMSIS库,以及如何调整编译器版本。同时,用户可能需要注意事项,比如备份项目,避免删除重要代码。 还要注意用户可能不了解如何找到CMSIS库或切换编译器版本,因此需要详细说明,例如在STM32Cube_FW中找到Drivers\CMSIS\Include目录。此外,引用[3]的方虽然简单,但可能导致问题,需要提醒用户谨慎操作。 最后,生成相关问题时要围绕CMSIS、编译器版本、报错处理等方面,帮助用户深入理解问题。</think>针对Keil编译时$core\_cm3.c$出现的4处报错问题,以下是分步解决方案: ### 解决方 1. **更新CMSIS库文件** - 从STM32Cube_FW软件包获取最新$core\_cm3.h$文件(路径:$Drivers\CMSIS\Include$) - 替换项目中旧版本头文件 - 添加配套文件:$cmsis\_armclang.h$、$cmsis\_compiler.h$、$cmsis\_version.h$[^1][^2] 2. **删除冗余文件** - 在工程目录中移除$core\_cm3.c$文件(CMSIS 5.7.0后不再需要该文件) - 保留$core\_cm3.h$作为核心头文件 3. **编译器版本控制** ```plaintext Project → Options → Target → ARM Compiler Version ``` - 优先选择Compiler V5(兼容旧工程) - 使用V6需配合CMSIS 5.8.0+ 4. **代码修正(应急方案)** - 定位报错行(通常为`__STREXB`/`__STREXH`等内联汇编指令) - 替换为: ```c __ASM volatile ("strexb %0, %1, [%2]" : "=r" (result) : "r" (value), "r" (addr) ); ``` - 或注释/删除问题代码(可能影响复位功能)[^3][^4] ### 注意事项 - 操作前备份工程 - 检查NVIC相关函数是否正常 - 推荐使用STM32CubeMX生成最新框架
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独坐寒江边

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值