仿pioneer3at的机器人,缺点当负载过大时,会产生跳齿等问题,效果一般电机使用的是富兴公司的伺服电机

控制参考:步进电机与ros通信,做的can与stm32通信,进行轮速的设定和位置的反馈,对反馈的编码值进行处理,得到移动平台的位置姿态,通过STM32的串口反馈给ros.加了遥控器遥控

程序可参考https://www.ncnynl.com/archives/201703/1416.html

将STM32程序下载到STM32上,ROS程序写好。

将STM32线连接到笔记本

roscore

sudo chmod a+rw /dev/ttyUSB0

rosrun base_controller base_controller

rosrun teleop_twist_keyboard teleop_twist_keyboard.py
就可以控制下位机小车移动了

#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include "rcc_conf.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "can.h"
#include "CONTACT.h"
#include "nvic_conf.h"
#include "odometry.h"
#include "tim2_5_6.h"
#include "stdbool.h"
#include <stdio.h>
#include "string.h"
#include "math.h"
char odometry_data[21]={0};   //发送给串口的里程计数据数组float odometry_right=0,odometry_left=0;//串口得到的左右轮速度
int i,j,m,t;/***********************************************  输入  *****************************************************************/extern float position_x,position_y,oriention,velocity_linear,velocity_angular;         //计算得到的里程计数值
extern u8 USART_RX_BUF[USART_REC_LEN];     //串口接收缓冲,最大USART_REC_LEN个字节.
extern u16 USART_RX_STA;                   //串口接收状态标记    extern float Milemeter_L_Motor,Milemeter_R_Motor;     //dt时间内的左右轮速度,用于里程计计算u8 main_sta=0; //用作处理主函数各种if,去掉多余的flag(1打印里程计)(2调用计算里程计数据函数)(3串口接收成功)(4串口接收失败)union recieveData  //接收到的数据
{float d;    //左右轮速度unsigned char data[4];
}leftdata,rightdata;       //接收的左右轮数据union odometry  //里程计数据共用体
{float odoemtry_float;unsigned char odometry_char[4];
}x_data,y_data,theta_data,vel_linear,vel_angular;     //要发布的里程计数据,分别为:X,Y方向移动的距离,当前角度,线速度,角速度int main(void)
{     unsigned char key_485;u8 i=0,t=0;delay_init();             //延时函数初始化      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级uart_init(115200);         //串口初始化为115200LED_Init();                  //初始化与LED连接的硬件接口LCD_Init();                   //初始化LCD    KEY_Init();                //按键初始化             CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//CAN初始化环回模式,波特率500Kbps RCC_Configuration();      //系统时钟配置        TIM2_PWM_Init();          //PWM输出初始化TIM5_Configuration();     //速度计算定时器初始化TIM1_Configuration();     //里程计发布定时器初始化NVIC_Configuration();     //中断优先级配置MOTOR_init();//电机初始化while(1){key_485=KEY_Scan(0);if (key_485==1){MOTOR_stop();}if (key_485==2){MOTOR_speed(300,300);} if(main_sta&0x01)//执行发送里程计数据步骤{//里程计数据获取x_data.odoemtry_float=position_x;//单位mmy_data.odoemtry_float=position_y;//单位mmtheta_data.odoemtry_float=oriention;//单位radvel_linear.odoemtry_float=velocity_linear;//单位mm/svel_angular.odoemtry_float=velocity_angular;//单位rad/sLCD_ShowxNum(60,80,210,24,24,position_x);  LCD_ShowxNum(90,80,210,24,24,position_y);             //将所有里程计数据存到要发送的数组for(j=0;j<4;j++){odometry_data[j]=x_data.odometry_char[j];odometry_data[j+4]=y_data.odometry_char[j];odometry_data[j+8]=theta_data.odometry_char[j];odometry_data[j+12]=vel_linear.odometry_char[j];odometry_data[j+16]=vel_angular.odometry_char[j];}odometry_data[20]='\n';//添加结束符//发送数据要串口for(i=0;i<21;i++){USART_ClearFlag(USART1,USART_FLAG_TC);  //在发送第一个数据前加此句,解决第一个数据不能正常发送的问题                USART_SendData(USART1,odometry_data[i]);//发送一个字节到串口    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);    //等待发送结束        LCD_ShowString(30,80,210,24,24,"Send");                }main_sta&=0xFE;//执行计算里程计数据步骤}if(main_sta&0x02)//执行计算里程计数据步骤{odometry(Milemeter_R_Motor,Milemeter_L_Motor);//计算里程计main_sta&=0xFD;//执行发送里程计数据步骤}if(main_sta&0x08)        //当发送指令没有正确接收时{USART_ClearFlag(USART1,USART_FLAG_TC);  //在发送第一个数据前加此句,解决第一个数据不能正常发送的问题for(m=0;m<3;m++){USART_SendData(USART1,0x00);    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);}        USART_SendData(USART1,'\n');    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);    main_sta&=0xF7;}if(USART_RX_STA&0x8000)  // 串口1接收函数{            LCD_ShowString(30,100,210,24,24,"Rec");//接收左右轮速度for(t=0;t<4;t++){rightdata.data[t]=USART_RX_BUF[t];leftdata.data[t]=USART_RX_BUF[t+4];}//储存左右轮速度odometry_right=rightdata.d;//单位mm/sodometry_left=leftdata.d;//单位mm/sLCD_ShowxNum(60,120,210,24,24,odometry_right);LCD_ShowxNum(60,140,210,24,24,odometry_left);USART_RX_STA=0;//清楚接收标志位MOTOR_speed(rightdata.d,leftdata.d);     //将接收到的左右轮速度赋给小车    }}}
/******************************************************************
基于串口通信的ROS小车基础控制器,功能如下:
1.实现ros控制数据通过固定的格式和串口通信,从而达到控制小车的移动
2.订阅了/cmd_vel主题,只要向该主题发布消息,就能实现对控制小车的移动
3.发布里程计主题/odm串口通信说明:
1.写入串口
(1)内容:左右轮速度,单位为mm/s
(2)格式:10字节,[右轮速度4字节][左轮速度4字节][结束符"\r\n"2字节]
2.读取串口
(1)内容:小车x,y坐标,方向角,线速度,角速度,单位依次为:mm,mm,rad,mm/s,rad/s
(2)格式:21字节,[X坐标4字节][Y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符"\n"1字节]
*******************************************************************/
#include "ros/ros.h"  //ros需要的头文件
#include <geometry_msgs/Twist.h>
#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h>
//以下为串口通讯需要的头文件
#include <string>
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <math.h>
#include "serial/serial.h"
/****************************************************************************/
using std::string;
using std::exception;
using std::cout;
using std::cerr;
using std::endl;
using std::vector;
/*****************************************************************************/
float ratio = 1000.0f ;   //转速转换比例,执行速度调整比例
float D = 0.412f ;    //两轮间距,单位是m
float linear_temp=0,angular_temp=0;//暂存的线速度和角速度
/****************************************************/
unsigned char data_terminal0=0x0d;  //“/r"字符
unsigned char data_terminal1=0x0a;  //“/n"字符
unsigned char speed_data[10]={0};   //要发给串口的数据
string rec_buffer;  //串口数据接收变量//发送给下位机的左右轮速度,里程计的坐标和方向
union floatData //union的作用为实现char数组和float之间的转换
{float d;unsigned char data[4];
}right_speed_data,left_speed_data,position_x,position_y,oriention,vel_linear,vel_angular;
/************************************************************/
void callback(const geometry_msgs::Twist & cmd_input)//订阅/cmd_vel主题回调函数
{string port("/dev/ttyUSB0");    //小车串口号unsigned long baud = 115200;    //小车串口波特率serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000)); //配置串口angular_temp = cmd_input.angular.z ;//获取/cmd_vel的角速度,rad/slinear_temp = cmd_input.linear.x ;//获取/cmd_vel的线速度.m/s//将转换好的小车速度分量为左右轮速度left_speed_data.d = linear_temp - 0.5f*angular_temp*D ;right_speed_data.d = linear_temp + 0.5f*angular_temp*D ;//left_speed_data.d=angular_temp;//right_speed_data.d=linear_temp;//存入数据到要发布的左右轮速度消息left_speed_data.d*=ratio;   //放大1000倍,mm/sright_speed_data.d*=ratio;//放大1000倍,mm/sfor(int i=0;i<4;i++)    //将左右轮速度存入数组中发送给串口{speed_data[i]=right_speed_data.data[i];speed_data[i+4]=left_speed_data.data[i];}//在写入串口的左右轮速度数据后加入”/r/n“speed_data[8]=data_terminal0;speed_data[9]=data_terminal1;//写入数据到串口my_serial.write(speed_data,10);
}
int main(int argc, char **argv)
{string port("/dev/ttyUSB0");//小车串口号unsigned long baud = 115200;//小车串口波特率serial::Serial my_serial(port, baud, serial::Timeout::simpleTimeout(1000));//配置串口ros::init(argc, argv, "base_controller");//初始化串口节点ros::NodeHandle n;  //定义节点进程句柄ros::Subscriber sub = n.subscribe("cmd_vel", 20, callback); //订阅/cmd_vel主题ros::Publisher odom_pub= n.advertise<nav_msgs::Odometry>("odom", 20); //定义要发布/odom主题static tf::TransformBroadcaster odom_broadcaster;//定义tf对象geometry_msgs::TransformStamped odom_trans;//创建一个tf发布需要使用的TransformStamped类型消息nav_msgs::Odometry odom;//定义里程计对象geometry_msgs::Quaternion odom_quat; //四元数变量//定义covariance矩阵,作用为解决文职和速度的不同测量的不确定性float covariance[36] = {0.01,   0,    0,     0,     0,     0,  // covariance on gps_x0,  0.01, 0,     0,     0,     0,  // covariance on gps_y0,  0,    99999, 0,     0,     0,  // covariance on gps_z0,  0,    0,     99999, 0,     0,  // large covariance on rot x0,  0,    0,     0,     99999, 0,  // large covariance on rot y0,  0,    0,     0,     0,     0.01};  // large covariance on rot z //载入covariance矩阵for(int i = 0; i < 36; i++){odom.pose.covariance[i] = covariance[i];;}       ros::Rate loop_rate(10);//设置周期休眠时间while(ros::ok()){rec_buffer =my_serial.readline(25,"\n");    //获取串口发送来的数据const char *receive_data=rec_buffer.data(); //保存串口发送来的数据if(rec_buffer.length()==21) //串口接收的数据长度正确就处理并发布里程计数据消息{for(int i=0;i<4;i++)//提取X,Y坐标,方向,线速度,角速度{position_x.data[i]=receive_data[i];position_y.data[i]=receive_data[i+4];oriention.data[i]=receive_data[i+8];vel_linear.data[i]=receive_data[i+12];vel_angular.data[i]=receive_data[i+16];}//将X,Y坐标,线速度缩小1000倍position_x.d/=1000; //mposition_y.d/=1000; //mvel_linear.d/=1000; //m/s//里程计的偏航角需要转换成四元数才能发布odom_quat = tf::createQuaternionMsgFromYaw(oriention.d);//将偏航角转换成四元数//载入坐标(tf)变换时间戳odom_trans.header.stamp = ros::Time::now();//发布坐标变换的父子坐标系odom_trans.header.frame_id = "odom";     odom_trans.child_frame_id = "base_footprint";       //tf位置数据:x,y,z,方向odom_trans.transform.translation.x = position_x.d;odom_trans.transform.translation.y = position_y.d;odom_trans.transform.translation.z = 0.0;odom_trans.transform.rotation = odom_quat;        //发布tf坐标变化odom_broadcaster.sendTransform(odom_trans);//载入里程计时间戳odom.header.stamp = ros::Time::now(); //里程计的父子坐标系odom.header.frame_id = "odom";odom.child_frame_id = "base_footprint";       //里程计位置数据:x,y,z,方向odom.pose.pose.position.x = position_x.d;     odom.pose.pose.position.y = position_y.d;odom.pose.pose.position.z = 0.0;odom.pose.pose.orientation = odom_quat;       //载入线速度和角速度odom.twist.twist.linear.x = vel_linear.d;//odom.twist.twist.linear.y = odom_vy;odom.twist.twist.angular.z = vel_angular.d;    //发布里程计odom_pub.publish(odom);ros::spinOnce();//周期执行loop_rate.sleep();//周期休眠}//程序周期性调用//ros::spinOnce();  //callback函数必须处理所有问题时,才可以用到}return 0;
}

键盘控制

#!/usr/bin/env pythonfrom __future__ import print_functionimport roslib; roslib.load_manifest('teleop_twist_keyboard')
import rospyfrom geometry_msgs.msg import Twistimport sys, select, termios, ttymsg = """
Reading from the keyboard  and Publishing to Twist!
---------------------------
Moving around:u    i    oj    k    lm    ,    .For Holonomic mode (strafing), hold down the shift key:
---------------------------U    I    OJ    K    LM    <    >t : up (+z)
b : down (-z)anything else : stopq/z : increase/decrease max speeds by 10%
w/x : increase/decrease only linear speed by 10%
e/c : increase/decrease only angular speed by 10%CTRL-C to quit
"""moveBindings = {'i':(1,0,0,0),'o':(1,0,0,-1),'j':(1,0,0,1),'l':(1,0,0,-1),'u':(1,0,0,1),',':(-1,0,0,0),'.':(-1,0,0,1),'m':(-1,0,0,-1),'O':(1,-1,0,0),'I':(1,0,0,0),'J':(0,1,0,0),'L':(0,-1,0,0),'U':(1,1,0,0),'<':(-1,0,0,0),'>':(-1,-1,0,0),'M':(-1,1,0,0),'t':(0,0,1,0),'b':(0,0,-1,0),}speedBindings={'q':(1.1,1.1),'z':(.9,.9),'w':(1.1,1),'x':(.9,1),'e':(1,1.1),'c':(1,.9),}def getKey():tty.setraw(sys.stdin.fileno())select.select([sys.stdin], [], [], 0)key = sys.stdin.read(1)termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)return keydef vels(speed,turn):return "currently:\tspeed %s\tturn %s " % (speed,turn)if __name__=="__main__":settings = termios.tcgetattr(sys.stdin)pub = rospy.Publisher('cmd_vel', Twist, queue_size = 1)rospy.init_node('teleop_twist_keyboard')speed = rospy.get_param("~speed", 0.1)turn = rospy.get_param("~turn", 0.4)x = 0y = 0z = 0th = 0status = 0try:print(msg)print(vels(speed,turn))while(1):key = getKey()if key in moveBindings.keys():x = moveBindings[key][0]y = moveBindings[key][1]z = moveBindings[key][2]th = moveBindings[key][3]elif key in speedBindings.keys():speed = speed * speedBindings[key][0]turn = turn * speedBindings[key][1]print(vels(speed,turn))if (status == 14):print(msg)status = (status + 1) % 15else:x = 0y = 0z = 0th = 0if (key == '\x03'):breaktwist = Twist()twist.linear.x = x*speed; twist.linear.y = y*speed; twist.linear.z = z*speed;twist.angular.x = 0; twist.angular.y = 0; twist.angular.z = th*turnpub.publish(twist)except Exception as e:print(e)finally:twist = Twist()twist.linear.x = 0; twist.linear.y = 0; twist.linear.z = 0twist.angular.x = 0; twist.angular.y = 0; twist.angular.z = 0pub.publish(twist)termios.tcsetattr(sys.stdin, termios.TCSADRAIN, settings)

其他学习4个can转向电机4个rs485轮毂电机及4个can编码器

在linux控制电机程序为:https://download.csdn.net/download/jankin_by/10342919

调试最后总出现编码器CRC校验错误,怀疑为linux下多串口通信的问题

改为用单片机直接控制

https://download.csdn.net/download/jankin_by/10342947

为了调试方便加了遥控

自主设计的滑移转向机器人同步带传动stm32f103的can伺服电机控制相关推荐

  1. 探测距离机器人模型:通过超声波测距控制舵机转向,LED灯,语音播放,蜂鸣器(米思齐mixly,arduino)

    ** ------------探测距离机器人模型:通过超声波测距控制舵机转向,LED灯,语音播放,蜂鸣器(米思齐mixly,arduino) 一. 初始化设置 在初始化这里要先设置波特率.并且把初始超 ...

  2. 滑动转向机器人轮间距校准

    关注同名微信公众号"混沌无形",有趣好文! 原文链接: 差速驱动机器人轮间距校准(包含原文PDF百度云下载链接) 履带式机器人和四轮驱动移动机器人(SSMR)也是差速转向的范畴,更 ...

  3. MATLAB(SimMechanics)机器人可视化运动仿真-关节位置控制篇

    MATLAB(SimMechanics)机器人可视化运动仿真-关节位置控制篇 摘要: 一 导入机器人URDF模型 二 建立关节电机控制的物理模型 三 仿真结果 1-整体物理模型 2-各关节电机PID位 ...

  4. FANUC机器人外部启动程序,Plc控制机器人启动程序

    FANUC机器人外部启动程序,Plc控制机器人启动程序,自己总结的PDF文档,看了你就会了. ID:699613445434337

  5. 开发者说 | 地平线程序员奶爸带你玩转机器人开发平台 —— 第一期 手势控制

    在地平线工作了4年多了,原本是冲着地平线机器人,机器人这三个字来的地平线,结果很长一段时间地平线都没搞机器人,我倒是给孩子买了不少机器人. 比如这个, 手势操控机器人,东西不错,很便宜,但是得带个手套 ...

  6. agx 安装ros opencv_【ROS开源】Jetson Nano阿克曼转向机器人

    塔克创新出品的系列入门ROS智能机器人学习开发平台,包括麦克纳姆轮机器人,四轮差速机器人,三轮全向机器人,两轮差速机器人,阿克曼转向小车等平台.可实现SLAM建图导航.自动避障.雷达跟随.视觉巡线.三 ...

  7. agx 安装ros opencv_【树莓派ROS开源机器人】阿克曼转向机器人,最接近无人自动驾驶的人工智能机器人...

    塔克创新出品的系列入门ROS智能机器人学习开发平台,包括麦克纳姆轮机器人,四轮差速机器人,两轮差速机器人,阿克曼转向小车等平台.可实现SLAM建图导航.自动避障.雷达跟随.视觉巡线.三维建图.手机AP ...

  8. nao机器人行走速度_基于PID控制的NAO机器人循线行走技术研究

    基于 PID 控制的 NAO 机器人循线行走技术研究 秦 娇,王向华 [摘 要] 智能机器人的循线行走技术在工业安全领域具有重要意义.选用 NAO 机器人作为研究平台,创新点在于将其在平面上的运动学动 ...

  9. 《ROS2机器人建模URDF》8.4控制移动机器人轮子运动

    本系列教程作者:小鱼 公众号:鱼香ROS QQ交流群:139707339 教学视频地址:小鱼的B站 完整文档地址:鱼香ROS官网 版权声明:如非允许禁止转载与商业用途. 8.4 控制移动机器人轮子运动 ...

最新文章

  1. ORACLE 监听之ORA-12518ORA-00020
  2. CSS多行文本垂直居中
  3. 从部署 httpd 入手,理清 k8s 配置中的 containerPort、port、nodePort、targetPort
  4. 旧访客设计模式的新生活
  5. elasticsearch基本查询三(英文分词)match查询
  6. c python 传参数 数组_python函数传递数组参数吗
  7. JNA参数传递问题,Java数组
  8. JS:ES6-6 初识Symbol类型
  9. php读取西门子plc_第三方设备如何读取PLC数据
  10. Mysql 如何设置字段自动获取当前时间
  11. 细粒度情感分析在到餐场景中的应用
  12. java间接调用_无法解析类型 java.util.Map$Entry。从必需的 .class 文件间接引用了它...
  13. 富爸爸实现财务自由七步骤
  14. 税务系统服务器维护导致逾期申报了,山东省电子税务局逾期申报处罚等功能升级啦!...
  15. 亚马逊Amazon-API接口使用说明
  16. Netjava project 简单画板的实现
  17. Python爬取托福阅读练习题
  18. 计算机不小心删除怎么找回桌面,电脑桌面文件被误删怎么找回
  19. Unity:使用Catmull-Rom曲线创建道路模型
  20. 上海2022年10月月赛丙组 T5:组队竞赛

热门文章

  1. 通知栏快捷按钮自定义教程以及快捷面板提取的思路-转自魔趣论坛-lonyii2
  2. 语音+蓝牙控制灯泡的制作教程
  3. deep_learning_初学neural network
  4. 服务器容易维修吗,服务器维修简单吗
  5. 【通俗易懂的解释】HttpSession session = request.getSession(false);中的false是什么意思
  6. 自然语言处理新天地(之三[2]) (转)
  7. 基于组态王和S7-200 PLC的六层电梯8层电梯控制
  8. Linux 下python文件多行注释的方法
  9. 云鲸扫拖一体机器人说明书_让做家务变的更简单:云鲸智能扫拖一体机器人测评...
  10. matlab实验之简单识别手写0-9数字程序