简易agv小车自动导航控制协议

1/获取地图栅格
2/实体化 转换 
3/行走指令 调度优先处理
   1/比如 前面  10-100米 行走指令序列
   2/以     后面  0-10分钟 行走指令序列

4/处理栅格
5/转换计算成行走操作  
   1/速度
   2/绝对移动位置
   3/错误操作
   4/阻碍操作
   5/警报操作
   6/转向
   7/任务完成停止
  8/任务切换---跳转主线程

简易协议代码:

在这里插入图片描述

控制协议封包

控制协议解包

//
qt获取当前实时生成点位数据

qt 获取当前位置地图

定位数据校准

定位数据校准坐标

ros硬件
1/ros can 接口
下面代码转载

#include <ros/ros.h>
#include <ros/spinner.h>
#include <std_msgs/String.h>
#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h>
#include <geometry_msgs/Twist.h>
#include <std_msgs/String.h>
#include <std_msgs/Int8.h>
#include <std_msgs/Float32.h>
#include <std_msgs/Float32MultiArray.h>
#include <socketcan_bridge/topic_to_socketcan.h>
#include <socketcan_bridge/socketcan_to_topic.h>
#include <can_msgs/Frame.h>
#include <socketcan_interface/socketcan.h>
 #include <iostream>

#define LEFT_MOTOR_CAN_ID 0x601
#define RIGHT_MOTOR_CAN_ID 0x602

#define LEFT_MOTOR_PDO_ID 0x201
#define RIGHT_MOTOR_PDO_ID 0x202


#define DISTANCE_WHEELS  0.562
#define DIAMETER_WHEELS    0.169
#define PI 3.1415926
#define EXP_DOUBLE 1e-6

bool flag_send = false;
ros::Publisher roscan_send_message;

void setCANopenMotorToward(unsigned int ID, uint8_t toward)
{
ROS_INFO("Ready to send can_message : motor toward");
setlocale(LC_ALL, "");

uint8_t transition[8];
can_msgs::Frame can_frame;
memset(&transition, 0, sizeof(transition));

//只发送一个字节0x2F 发送两个字节0x2B 发送四个字节0x23 
transition[0] = 0x2F;

//设置电机方向的索引为607E低位在前高位在后
transition[1] = 0x7E;
transition[2] = 0x60;

//子索引为00
transition[3] = 0x00;

//设置方向,低位在前高位在后

transition[4] = toward;
transition[5] = 0x00;
transition[6] = 0x00;
transition[7] = 0x00;

can_frame.id = ID;

can_frame.is_extended = true;
can_frame.is_rtr = false;
can_frame.is_error = false;
can_frame.dlc = 8; //有效数据长度

for (uint8_t i = 0; i < can_frame.dlc; i++)
{

    can_frame.data[i] = transition[i];
}

roscan_send_message.publish(can_frame);

ROS_INFO("send messages succeed : work model shift");
}

void setCANopenMotorSpeed(unsigned int ID, double speed)
{
bool flag_sign = false;

if(speed < 0)
{
    flag_sign = true;
}

double rpm = fabs(speed);
int encoder_resolution = 10000;
int dec = rpm *512* encoder_resolution/1875;

if(flag_sign == true)
{
    dec = (~dec) + 1;
}

ROS_INFO("Ready to send can_message : motor speed  0x%X" , dec);
setlocale(LC_ALL, "");

uint8_t transition[8];
can_msgs::Frame can_frame;
memset(&transition, 0, sizeof(transition));

//设置轮子转速
unsigned int encode_tmp = 0xff;
transition[0] = dec&encode_tmp;
transition[1] = (dec>>8)&encode_tmp;
transition[2] = (dec>>16)&encode_tmp;
transition[3] = (dec>>24)&encode_tmp;

can_frame.id = ID;

can_frame.is_extended = true;
can_frame.is_rtr = false;
can_frame.is_error = false;
can_frame.dlc = 4; //有效数据长度

for (uint8_t i = 0; i < can_frame.dlc; i++)
{

    can_frame.data[i] = transition[i];
}

roscan_send_message.publish(can_frame);

ROS_INFO("send messages succeed : motor speed %X %X %X %X",transition[0],transition[1],transition[2],transition[3]);
}

void setCANopenMotorWorkMdl(unsigned int ID , uint8_t work_mdl)
{

ROS_INFO("Ready to send can_message : work model shift");
setlocale(LC_ALL, "");

uint8_t transition[8];
can_msgs::Frame can_frame;
memset(&transition, 0, sizeof(transition));

//只发送一个字节0x2F 发送两个字节0x2B 发送四个字节0x23
transition[0] = 0x2F;

//设置工作模式的索引为6060低位在前高位在后
transition[1] = 0x60;
transition[2] = 0x60;

//子索引为00
transition[3] = 0x00;

//位置模式是0 速度模式是3
transition[4] = work_mdl;

//剩下全部补0即可
transition[5] = 0x00;
transition[6] = 0x00;
transition[7] = 0x00;

can_frame.id = ID;

can_frame.is_extended = true;
can_frame.is_rtr = false;
can_frame.is_error = false;
can_frame.dlc = 8; //有效数据长度

for (uint8_t i = 0; i < can_frame.dlc; i++)
{

    can_frame.data[i] = transition[i];
}

roscan_send_message.publish(can_frame);

ROS_INFO("send messages succeed : work model shift");

}



void WorkMdlCallback(const std_msgs::Int8 & msg)
{
ROS_INFO("work model setting : %d" ,msg.data);
setCANopenMotorWorkMdl(LEFT_MOTOR_CAN_ID,static_cast<uint8_t>(msg.data));
setCANopenMotorWorkMdl(RIGHT_MOTOR_CAN_ID,static_cast<uint8_t>(msg.data));
//send_can_message();
}

void MotorSpeedCallback(const std_msgs::Float32MultiArray & msg)
{
ROS_INFO("motor speed setting : %f" ,msg.data[1]);
//如果是左轮
unsigned int id;
uint8_t dir;

if(msg.data.size() == 2)
{
    if(msg.data[0] < 0)
    {
        ROS_INFO("motor speed setting : left wheel");
        id = LEFT_MOTOR_PDO_ID;
    }
    //如果是右轮
    else if(msg.data[0] > 0)
    {
        ROS_INFO("motor speed setting : right wheel");
        id = RIGHT_MOTOR_PDO_ID;
    }
    setCANopenMotorSpeed(id,msg.data[1]);
}
else if(msg.data.size() == 3)
{
    id = LEFT_MOTOR_PDO_ID;
    setCANopenMotorSpeed(id,msg.data[1]);
    id = RIGHT_MOTOR_PDO_ID;
    setCANopenMotorSpeed(id,msg.data[2]);
}

}

void cmdVelCallback(const geometry_msgs::Twist & msg)
{
//    vel_left = (curr_cmd.lin - curr_cmd.ang * L/ 2.0) / left_wheel_radius;
//    vel_right = (curr_cmd.lin + curr_cmd.ang * L/ 2.0) / right_wheel_radius;
//    m/s
double v_line_x = msg.linear.x;
double v_angr_z = msg.angular.z;
double radius = DIAMETER_WHEELS / 2;
double dist_w = DISTANCE_WHEELS;

double vel_left = (v_line_x - v_angr_z * dist_w / 2.0) / radius;  // m/s
double vel_right = (v_line_x + v_angr_z * dist_w / 2.0) / radius;

double speed_left = vel_left * 2 * PI;     // rad/s
double speed_right = vel_right * 2 * PI;

speed_left *= 9.55; //rpm
speed_right *= 9.55;

unsigned int id;
id = LEFT_MOTOR_PDO_ID;
setCANopenMotorSpeed(id,speed_left);
id = RIGHT_MOTOR_PDO_ID;
setCANopenMotorSpeed(id,-speed_right);

}

int main(int argc, char **argv)
{

ros::init(argc, argv, "can_sender");
ros::NodeHandle n("~");

ros::Subscriber work_mdl_sub = n.subscribe("/work_mdl_shift" , 60 , WorkMdlCallback);
ros::Subscriber motor_speed_sub = n.subscribe("/motor_speed" , 60 , MotorSpeedCallback);

ros::Subscriber cmd_vel_sub = n.subscribe("/cmd_vel" , 60 , cmdVelCallback);

roscan_send_message = n.advertise<can_msgs::Frame>("/sent_messages", 100);

ros::spin();

}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的 AGV 小车控制协议包文档,供参考: # AGV 小车控制协议包文档 ## 协议概述 该协议用于控制 AGV 小车的运动。协议基于串口通信,要求发送方向接收方定期发送心跳包以保持连接。协议包格式如下: ``` +---------+---------+---------+---------+-----------+---------+ | 标识符 | 数据长度 | 指令码 | 子指令 | 数据内容 | 校验码 | +---------+---------+---------+---------+-----------+---------+ | 1 byte | 1 byte | 1 byte | 1 byte | n bytes | 1 byte | +---------+---------+---------+---------+-----------+---------+ ``` ## 包字段说明 ### 标识符 标识符为 0x55,表示该包为有效的控制包。 ### 数据长度 数据长度为整个数据包的长度,包括标识符、数据长度、指令码、子指令、数据内容和校验码。数据长度为 1 byte,范围为 0~255。 ### 指令码 指令码表示该包中的指令。指令码为 1 byte,具体取值如下: | 指令码 | 描述 | | ------ | ---- | | 0x01 | 控制 AGV 小车运动 | ### 子指令 子指令表示指令的具体操作。子指令为 1 byte,具体取值如下: | 指令码 | 子指令 | 描述 | | ------ | ------ | ---- | | 0x01 | 0x01 | AGV 小车向前移动 | | 0x01 | 0x02 | AGV 小车向后移动 | | 0x01 | 0x03 | AGV 小车向左移动 | | 0x01 | 0x04 | AGV 小车向右移动 | | 0x01 | 0x05 | AGV 小车停止运动 | ### 数据内容 数据内容为指令的参数,具体内容根据子指令不同而不同。数据内容长度为 0~253 bytes。 ### 校验码 校验码为整个包的校验和,计算方法为将标识符、数据长度、指令码、子指令和数据内容相加取低 8 位,然后取反。校验码长度为 1 byte。 ## 示例 下面是一个向前移动 1 米的示例: ``` +---------+---------+---------+---------+-----------------------+---------+ | 标识符 | 数据长度 | 指令码 | 子指令 | 数据内容 | 校验码 | +---------+---------+---------+---------+-----------------------+---------+ | 0x55 | 7 | 0x01 | 0x01 | 0x01, 0x00, 0x00, 0x01 | 0xA8 | +---------+---------+---------+---------+-----------------------+---------+ ``` 解释如下: - 标识符为 0x55,表示该包为有效的控制包。 - 数据长度为 7,表示该包总共有 7 个字节。 - 指令码为 0x01,表示该包中的指令为控制 AGV 小车运动。 - 子指令为 0x01,表示该包中的指令为向前移动。 - 数据内容为 0x01, 0x00, 0x00, 0x01,表示向前移动 1 米。 - 校验码为 0xA8,表示整个包的校验和为 0x57 + 0x07 + 0x01 + 0x01 + 0x01 + 0x00 + 0x00 + 0x01 = 0x6C,取反后为 0xA8。 ## 注意事项 - 数据长度不包括标识符和校验码,只包括指令码、子指令和数据内容。 - 数据内容的具体含义和取值需要根据具体情况协商。 - 校验码需要根据整个包的内容计算,确保数据的准确性和完整性。 - 发送方和接收方需要定期发送心跳包以保持连接。 - 协议的具体实现需要根据硬件平台和软件开发环境进行调整和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值