1、上位机系统的安装
本项目采用的系统配置为ubuntu 16.04+ROS Kinetic,采用的是工控机(大家也可以使用树莓派,这部分的安装参考博客:树莓派安装教程)
ubuntu16.04的安装比较简单这里不再赘述,系统镜像自行下载:云盘资料提取码:5vyc
安装好了ubuntu后大家就可以安装ros系统了。具体步骤如下:
1)、配置密钥
sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80 --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116
2)、更新
sudo apt-get update && sudo apt-get upgrade
3)、安装
sudo apt-get install ros-kinetic-desktop-full
4)、初始化rosdep(这一步大部分人可能会出现问题,解决办法参考我这篇博客的内容:看rosdep初始化那个位置)
sudo rosdep init
然后再执行
sudo rosdep init
接下来输入
rosdep update
5)、安装依赖包
sudo apt-get install python-rosinstall python-rosinstall-generator python-wstool build-essential
6)、测试ROS是否搭建成功
先运行
roscore
再开新终端
rosrun turtlesim turtlesim_node
如果结果正常,此时会出现一个图形界面,里面有只乌龟
ROS系统安装完成!!!
本项目所用的下位机为arduino所有其与上位机ros之间的通讯方式有大致两种一种是rosserial_arduino和ros_arduino_bridge,两种通讯方式各有优缺点。本项目选择用rosserial_arduino作为通讯方式(此方式相当于把arduino下位机当成一个ros节点,接收发发布话题进行数据的传输)
1、在ubuntu中安装arduino 18.0
这部分安装过程可以参考这篇文章:arduino 1.8安装教程
2、rosserial_arduino安装
这部分参考:rosserial_arduino安装教程
3、下位机的程序
这部分程序和之前说的大部分是一样的,只是这部分加了
#if (ARDUINO >= 100)
#include
#else
#include
#endif
#include
#include
#include
#include
#include
#define DIR1 4 //motor1方向控制引脚、pwm速度控制引脚定义
#define pwm1 5
#define DIR2 6 //motor2方向控制引脚、pwm速度控制引脚定义
#define pwm2 7
#define DIR3 8 //motor3方向控制引脚、pwm速度控制引脚定义
#define pwm3 9
#define DIR4 10 //motor4方向控制引脚、pwm速度控制引脚定义
#define pwm4 11
#define motorcount1A 19 //motor1编码器A、B引脚定义
#define motorcount1B 15
#define motorcount2A 18 //motor2编码器A、B引脚定义
#define motorcount2B 14
#define motorcount3A 21 //motor3编码器A、B引脚定义
#define motorcount3B 17
#define motorcount4A 20 //motor4编码器A、B引脚定义
#define motorcount4B 16
int max_v=50;
float a=0.36/2,b=0.265/2;
float car_vx=0; //linear x
float car_vy=0;
float car_yaw=0; //anglear z
float pub_car_vx=0; //linear x
float pub_car_vy=0;
float pub_car_yaw=0; //anglear z
float PotBuffer1=0; //各轮的速度
float PotBuffer2=0;
float PotBuffer3=0;
float PotBuffer4=0;
int PotBuffer=0; //车子的速度矢量
volatile float motor1=0; //中断变量,1号轮子脉冲计数
float v_motor_1=0;
volatile float motor2=0; //中断变量,2号轮子脉冲计数
float v_motor_2=0;
volatile float motor3=0; //中断变量,3号轮子脉冲计数
float v_motor_3=0;
volatile float motor4=0; //中断变量,4号轮子脉冲计数
float v_motor_4=0;
float kp=1.6,ki=0.8,kd=0;
int dir1=0,dir2=0,dir3=0,dir4=0;
int P1=0,P2=0,P3=0,P4=0;
ros::NodeHandle nh; //节点句柄
void generate_motor_v()
{
PotBuffer1=car_vx-car_vy+car_yaw*(a+b);
PotBuffer2=car_vx+car_vy-car_yaw*(a+b);
PotBuffer3=car_vx-car_vy-car_yaw*(a+b);
PotBuffer4=car_vx+car_vy+car_yaw*(a+b);
P1=Incremental_Pi(v_motor_1,PotBuffer1);
// P2=Incremental_Pi(v_motor_2,PotBuffer2);
// P3=Incremental_Pi(v_motor_3,PotBuffer3);
// P4=Incremental_Pi(v_motor_4,PotBuffer4);
if(PotBuffer1>=max_v)PotBuffer1=max_v;
else if(PotBuffer1<-max_v)PotBuffer1=-max_v;
if(PotBuffer2>=max_v)PotBuffer2=max_v;
else if(PotBuffer2<-max_v)PotBuffer2=-max_v;
if(PotBuffer3>=max_v)PotBuffer3=max_v;
else if(PotBuffer3<-max_v)PotBuffer3=-max_v;
if(PotBuffer4>=max_v)PotBuffer4=max_v;
else if(PotBuffer4<-max_v)PotBuffer4=-max_v;
if(PotBuffer1>=0){digitalWrite(DIR1,LOW);dir1=0;}
else if(PotBuffer1<0){digitalWrite(DIR1,HIGH);dir1=1;}
if(PotBuffer2>=0){digitalWrite(DIR2,HIGH);dir2=0;}
else if(PotBuffer2<0){digitalWrite(DIR2,LOW);dir2=1;}
if(PotBuffer3>=0){digitalWrite(DIR3,HIGH);dir3=0;}
else if(PotBuffer3<0){digitalWrite(DIR3,LOW);dir3=1;}
if(PotBuffer4>=0){digitalWrite(DIR4,LOW);dir4=0;}
else if(PotBuffer4<0){digitalWrite(DIR4,HIGH);dir4=1;}
}
void motor_control(const geometry_msgs::Twist& cmd_vel) //订阅话题时触发打中断函数
{
car_vx = cmd_vel.linear.x*100; // Cm/s
car_yaw=cmd_vel.angular.z*100;
car_vy=cmd_vel.linear.y;
read_motor_v();
generate_motor_v();
}
//ros::Subscriber sub("motor_vel", motor_cmd); //订阅“motor_vel”话题的数据(速度话题)
ros::Subscriber sub1("/cmd_vel", motor_control); //订阅cmd_vel话题的数据(方向话题)
geometry_msgs::Twist vel;
ros::Publisher chatter("vel_motor",&vel); //发布车的速度话题
void read_motor_v()
{
unsigned long nowtime=0; //机时时间定义
motor1=0; //脉冲初始化
motor2=0;
motor3=0;
motor4=0;
nowtime=millis()+50;
while(millis()=max_v){
// pwm=max_v;
// }
return pwm; //增量输出
}
void setup(){
pinMode(13, OUTPUT);
pinMode(motorcount1A,INPUT); //编码器引脚设置
pinMode(motorcount1B,INPUT);
pinMode(motorcount2A,INPUT);
pinMode(motorcount2B,INPUT);
pinMode(motorcount3A,INPUT);
pinMode(motorcount3B,INPUT);
pinMode(motorcount4A,INPUT);
pinMode(motorcount4B,INPUT);
nh.initNode(); //节点句柄
nh.advertise(chatter); //发布消息的准备
//nh.subscribe(sub); //订阅消息
nh.subscribe(sub1);
pinMode(12,OUTPUT);
pinMode(pwm1,OUTPUT); //motor方向和速度引脚设置
pinMode(DIR1,OUTPUT);
pinMode(pwm2,OUTPUT);
pinMode(DIR2,OUTPUT);
pinMode(pwm3,OUTPUT);
pinMode(DIR3,OUTPUT);
pinMode(pwm4,OUTPUT);
pinMode(DIR4,OUTPUT);
digitalWrite(12,HIGH);
}
void loop(){
read_motor_v();
vel.linear.x=pub_car_vx; //获取发布打数据
vel.linear.y=pub_car_vy;
vel.linear.z=0.0;
vel.angular.z=pub_car_yaw;
vel.angular.x=0.0;
vel.angular.y=0.0;
chatter.publish(&vel); //发布消息
nh.spinOnce();
analogWrite(pwm1,abs(PotBuffer1)); //发送脉冲给电机
analogWrite(pwm2,abs(PotBuffer2));
analogWrite(pwm3,abs(PotBuffer3));
analogWrite(pwm4,abs(PotBuffer4));
delay(1);
}
代码上传以后,需要对串口进行授权
sudo chmod 777 /dev/ttyACM0
末尾的端口号大家根据自己的串口情况来修改
然后运行
roscore
再开一个新的终端运行
rosrun rosserial_paython serial_node.py /dev/ttyACM0
这部分完成后大家就可以通过发布cmd_vel话题来控制自己的小车了。
大家可以运行
rosrun turtlesim turtle_teleop_key
使用键盘来发布cmd_vel速度话题控制小车。
这部分结束,下一章我们将开始我们的ros导航之旅!!!