目录

​​1.点动​​

​​2.长动​​

​​3.esp32的arduino端代码​​

​​4.效果展示​​

​​参考链接​​


2121-10-07

这里的控制通过按键盘上的wsad达到小车前后左右的效果。

长动,顾名思义,就是按一下w,小车就开始前进,知道输入停止按键,小车就停止。

与之对应的是点动,就是按住w按键,小车开始前进,直到松开按键,小车就停止。

我们通过/command这个话题来传递命令消息,点动与长动只有上位机(pc)上的程序不同,esp32端的程序是一样的。

1.点动

直接看代码,点动的话,当我们在键盘终端敲击一下w这个按键,则程序会往/command话题发送一个话题消息,esp32接受到消息之后,解析消息数据从而判断命令,再驱动电机控制小车动作。

//读取键盘输入

#include <ros/ros.h>

#include <std_msgs/UInt16.h>

#include <stdio.h>

#include <unistd.h>

#include <linux/input.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <termio.h>



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

{

setlocale(LC_ALL,"");

ros::init(argc,argv,"teleop_controlCar");

ros::NodeHandle nh;



ros::Publisher pub = nh.advertise<std_msgs::UInt16>("/command",1000);



std_msgs::UInt16 command_car;

command_car.data=0;

ros::Rate r(50);

printf("----Control panel----\n");

printf("Please input command!\n");

printf(" w \n");

printf("a s d\n");



//设置终端参数,关闭终端回显

struct termios new_settings;

tcgetattr(0,&new_settings);

new_settings.c_lflag &= (~ECHO);

new_settings.c_lflag &= (~ICANON);

new_settings.c_cc[VTIME] = 0;

new_settings.c_cc[VMIN] = 1;

tcsetattr(0,TCSANOW,&new_settings);



//以下为键盘输入检测

int fd_kb;

int flag_ke=1;//0:按下 1:释放;

struct input_event event_kb;



fd_kb = open("/dev/input/event2", O_RDONLY); //键盘输入

if (fd_kb <= 0)

{

printf("open device error\n");

return 0;

}



while (ros::ok())

{

if (read(fd_kb, &event_kb, sizeof(event_kb)) == sizeof(event_kb)) //event_kb有24个字节

{

if (event_kb.type == EV_KEY)

{

if (event_kb.value == 1) //1表示按下,0表示释放

{

if(flag_ke==1)

{

switch(event_kb.code)

{

case KEY_W:command_car.data=1;pub.publish(command_car);break;

case KEY_A:command_car.data=3;pub.publish(command_car);break;

case KEY_S:command_car.data=2;pub.publish(command_car);break;

case KEY_D:command_car.data=4;pub.publish(command_car);break;

case KEY_KP1:command_car.data=5;pub.publish(command_car);break;

case KEY_KP2:command_car.data=6;pub.publish(command_car);break;

case KEY_KP4:command_car.data=7;pub.publish(command_car);break;

case KEY_KP5:command_car.data=8;pub.publish(command_car);break;

case KEY_KP7:command_car.data=9;pub.publish(command_car);break;

case KEY_KP8:command_car.data=10;pub.publish(command_car);break;

case KEY_Q:

new_settings.c_lflag &= ECHO;

new_settings.c_lflag &= ICANON;

tcsetattr(0,TCSANOW,&new_settings);

printf("Finished!");

close(fd_kb);

return 0;

default:command_car.data=0;pub.publish(command_car);

}

flag_ke=0;

}

else

flag_ke=0;

}

else if(event_kb.value == 0)

{

if(flag_ke==0)

{

command_car.data=0;

pub.publish(command_car);

flag_ke=1;

}

else

flag_ke=1;

}

}

}

}

close(fd_kb);

return 0;

}

2.长动

长动的作用机制,当我们按下键盘上的w这个按键的时候,程序会往/command这个话题发送一个消息,数据内容为1(即前进),这个时候esp32就会受到话题消息,然后控制小车前进,当我们松开键盘,则程序立即往/command话题发布停止的消息,esp32就立即控制小车停止。

#include <ros/ros.h>
#include <std_msgs/UInt16.h>
#include <termio.h>
#include <stdio.h>

#define KEYCODE_W 0x77 //command 1 forward
#define KEYCODE_A 0x61 //command 3 left
#define KEYCODE_S 0x73 //command 2 backward
#define KEYCODE_D 0x64 //command 4 right
#define KEYCODE_1 0x31 //command 5 motor1 right
#define KEYCODE_2 0x32 //command 6 motor1 left
#define KEYCODE_4 0x34 //command 7 motor2 right
#define KEYCODE_5 0x35 //command 8 motor2 left
#define KEYCODE_7 0x37 //command 9 motor3 right
#define KEYCODE_8 0x38 //command 10 motor3 left

int scanKeyboard()
{
int in;

struct termios new_settings;
struct termios stored_settings;
//设置终端参数
tcgetattr(0,&stored_settings);
new_settings = stored_settings;
new_settings.c_lflag &= (~ECHO);
new_settings.c_lflag &= (~ICANON);

new_settings.c_cc[VTIME] = 0;
tcgetattr(0,&stored_settings);
new_settings.c_cc[VMIN] = 1;
tcsetattr(0,TCSANOW,&new_settings);
in = getchar();
tcsetattr(0,TCSANOW,&stored_settings);

return in;
}
//测试函数
int main(int argc, char *argv[])
{

setlocale(LC_ALL,"");
ros::init(argc,argv,"teleop_controlCar");
ros::NodeHandle nh;
//command 0:stop 1:forward 2:backward 3:left 4:right 5:motor1 6:motor2 7:motor3
ros::Publisher pub = nh.advertise<std_msgs::UInt16>("/command",1000);

std_msgs::UInt16 command_car;
command_car.data=0;

ros::Rate r(50);
while(ros::ok()){
switch(scanKeyboard())
{
case KEYCODE_W:command_car.data=1;break;
case KEYCODE_A:command_car.data=3;break;
case KEYCODE_S:command_car.data=2;break;
case KEYCODE_D:command_car.data=4;break;
case KEYCODE_1:command_car.data=5;break;
case KEYCODE_2:command_car.data=6;break;
case KEYCODE_4:command_car.data=7;break;
case KEYCODE_5:command_car.data=8;break;
case KEYCODE_7:command_car.data=9;break;
case KEYCODE_8:command_car.data=10;break;
default:command_car.data=0;
}
pub.publish(command_car);
r.sleep();
}
}

3.esp32的arduino端代码

#include <WiFi.h>
#include <ros.h>
#include <std_msgs/UInt16.h>
#include <std_msgs/String.h>

#define LED_BUILTIN 2
#define delay_flash 5

//电机引脚定义
#define MOTO_1_PIN_1 14 //前后左右
#define MOTO_1_PIN_2 15
#define MOTO_2_PIN_1 13
#define MOTO_2_PIN_2 12

#define MOTO_3_PIN_1 2 //抬起下落
#define MOTO_3_PIN_2 0
#define MOTO_4_PIN_1 4
#define MOTO_4_PIN_2 16

#define MOTO_5_PIN_1 17 //吊臂弯曲伸直
#define MOTO_5_PIN_2 5
#define MOTO_6_PIN_1 18
#define MOTO_6_PIN_2 19

#define MOTO_7_PIN_1 27 //挖斗挖掘放下
#define MOTO_7_PIN_2 26
#define MOTO_8_PIN_1 25
#define MOTO_8_PIN_2 33

//esp32作为sta模式,接入局域网路由器WiFi名和密码
const char* ssid = "Zhitong";
const char* password = "95359897";

IPAddress server(192, 168, 191, 2); // ROS server的IP

ros::NodeHandle nh;
std_msgs::String str_msg;
std_msgs::UInt16 command_car;
ros::Publisher chatter("chatter", &str_msg);


char hello[20] = "ESP32 wifi alive!";

WiFiClient client;

class WiFiHardware {

public:
WiFiHardware() {};

void init() {
// do your initialization here. this probably includes TCP server/client setup
client.connect(server, 11411);
}

// read a byte from the serial port. -1 = failure
int read() {
// implement this method so that it reads a byte from the TCP connection and returns it
// you may return -1 is there is an error; for example if the TCP connection is not open
return client.read(); //will return -1 when it will works
}

// write data to the connection to ROS
void write(uint8_t* data, int length) {
// implement this so that it takes the arguments and writes or prints them to the TCP connection
for(int i=0; i<length; i++)
client.write(data[i]);
}

// returns milliseconds since start of program
unsigned long time() {
return millis(); // easy; did this one for you
}
};

//初始化WiFi
void setupWiFi()
{
WiFi.begin(ssid, password);
Serial.print("\nConnecting to "); Serial.println(ssid);
uint8_t i = 0;

while (WiFi.status() != WL_CONNECTED) {
i++;
delay(500);
Serial.print(".");
if (i > 120) { //60秒后如果还是连接不上,就判定为连接超时
Serial.print("连接超时!请检查网络环境");
break;
}
}

if(i == 21){
Serial.print("Could not connect to"); Serial.println(ssid);
while(1) delay(500);
}
Serial.print("Ready! Use ");
Serial.print(WiFi.localIP());
Serial.println(" to access client");
}

void init_motorPin(){
pinMode(MOTO_1_PIN_1,OUTPUT);
pinMode(MOTO_1_PIN_2,OUTPUT);
pinMode(MOTO_2_PIN_1,OUTPUT);
pinMode(MOTO_2_PIN_2,OUTPUT);
pinMode(MOTO_3_PIN_1,OUTPUT);
pinMode(MOTO_3_PIN_2,OUTPUT);
pinMode(MOTO_4_PIN_1,OUTPUT);
pinMode(MOTO_4_PIN_2,OUTPUT);
pinMode(MOTO_5_PIN_1,OUTPUT);
pinMode(MOTO_5_PIN_2,OUTPUT);
pinMode(MOTO_6_PIN_1,OUTPUT);
pinMode(MOTO_6_PIN_2,OUTPUT);
pinMode(MOTO_7_PIN_1,OUTPUT);
pinMode(MOTO_7_PIN_2,OUTPUT);
pinMode(MOTO_8_PIN_1,OUTPUT);
pinMode(MOTO_8_PIN_2,OUTPUT);
delay(delay_flash);
stop_car();
}

void forward_car(){
digitalWrite(MOTO_1_PIN_1,HIGH);
digitalWrite(MOTO_1_PIN_2,LOW);
digitalWrite(MOTO_2_PIN_1,HIGH);
digitalWrite(MOTO_2_PIN_2,LOW);
digitalWrite(MOTO_3_PIN_1,HIGH);
digitalWrite(MOTO_3_PIN_2,LOW);
digitalWrite(MOTO_4_PIN_1,HIGH);
digitalWrite(MOTO_4_PIN_2,LOW);
delay(delay_flash);
digitalWrite(MOTO_1_PIN_1,HIGH);
digitalWrite(MOTO_1_PIN_2,LOW);
digitalWrite(MOTO_2_PIN_1,HIGH);
digitalWrite(MOTO_2_PIN_2,LOW);
digitalWrite(MOTO_3_PIN_1,HIGH);
digitalWrite(MOTO_3_PIN_2,LOW);
digitalWrite(MOTO_4_PIN_1,HIGH);
digitalWrite(MOTO_4_PIN_2,LOW);

}

void backward_car(){
digitalWrite(MOTO_1_PIN_1,LOW);
digitalWrite(MOTO_1_PIN_2,HIGH);
digitalWrite(MOTO_2_PIN_1,LOW);
digitalWrite(MOTO_2_PIN_2,HIGH);
digitalWrite(MOTO_3_PIN_1,LOW);
digitalWrite(MOTO_3_PIN_2,HIGH);
digitalWrite(MOTO_4_PIN_1,LOW);
digitalWrite(MOTO_4_PIN_2,HIGH);
delay(delay_flash);
digitalWrite(MOTO_1_PIN_1,LOW);
digitalWrite(MOTO_1_PIN_2,HIGH);
digitalWrite(MOTO_2_PIN_1,LOW);
digitalWrite(MOTO_2_PIN_2,HIGH);
digitalWrite(MOTO_3_PIN_1,LOW);
digitalWrite(MOTO_3_PIN_2,HIGH);
digitalWrite(MOTO_4_PIN_1,LOW);
digitalWrite(MOTO_4_PIN_2,HIGH);
}

void left_car(){
digitalWrite(MOTO_1_PIN_1,LOW);
digitalWrite(MOTO_1_PIN_2,HIGH);
digitalWrite(MOTO_2_PIN_1,HIGH);
digitalWrite(MOTO_2_PIN_2,LOW);
digitalWrite(MOTO_3_PIN_1,HIGH);
digitalWrite(MOTO_3_PIN_2,LOW);
digitalWrite(MOTO_4_PIN_1,LOW);
digitalWrite(MOTO_4_PIN_2,HIGH);
delay(delay_flash);
digitalWrite(MOTO_1_PIN_1,LOW);
digitalWrite(MOTO_1_PIN_2,HIGH);
digitalWrite(MOTO_2_PIN_1,HIGH);
digitalWrite(MOTO_2_PIN_2,LOW);
digitalWrite(MOTO_3_PIN_1,HIGH);
digitalWrite(MOTO_3_PIN_2,LOW);
digitalWrite(MOTO_4_PIN_1,LOW);
digitalWrite(MOTO_4_PIN_2,HIGH);
}

void right_car(){
digitalWrite(MOTO_1_PIN_1,HIGH);
digitalWrite(MOTO_1_PIN_2,LOW);
digitalWrite(MOTO_2_PIN_1,LOW);
digitalWrite(MOTO_2_PIN_2,HIGH);
digitalWrite(MOTO_3_PIN_1,LOW);
digitalWrite(MOTO_3_PIN_2,HIGH);
digitalWrite(MOTO_4_PIN_1,HIGH);
digitalWrite(MOTO_4_PIN_2,LOW);
delay(delay_flash);
digitalWrite(MOTO_1_PIN_1,HIGH);
digitalWrite(MOTO_1_PIN_2,LOW);
digitalWrite(MOTO_2_PIN_1,LOW);
digitalWrite(MOTO_2_PIN_2,HIGH);
digitalWrite(MOTO_3_PIN_1,LOW);
digitalWrite(MOTO_3_PIN_2,HIGH);
digitalWrite(MOTO_4_PIN_1,HIGH);
digitalWrite(MOTO_4_PIN_2,LOW);
}

void motor5_right(){
digitalWrite(MOTO_5_PIN_1,HIGH);
digitalWrite(MOTO_5_PIN_2,LOW);
delay(delay_flash);
digitalWrite(MOTO_5_PIN_1,HIGH);
digitalWrite(MOTO_5_PIN_2,LOW);
}

void motor5_left(){
digitalWrite(MOTO_5_PIN_1,LOW);
digitalWrite(MOTO_5_PIN_2,HIGH);
delay(delay_flash);
digitalWrite(MOTO_5_PIN_1,LOW);
digitalWrite(MOTO_5_PIN_2,HIGH);
}

void motor6_right(){
digitalWrite(MOTO_6_PIN_1,HIGH);
digitalWrite(MOTO_6_PIN_2,LOW);
delay(delay_flash);
digitalWrite(MOTO_6_PIN_1,HIGH);
digitalWrite(MOTO_6_PIN_2,LOW);
}

void motor6_left(){
digitalWrite(MOTO_6_PIN_1,LOW);
digitalWrite(MOTO_6_PIN_2,HIGH);
delay(delay_flash);
digitalWrite(MOTO_6_PIN_1,LOW);
digitalWrite(MOTO_6_PIN_2,HIGH);
}

void motor7_right(){
digitalWrite(MOTO_7_PIN_1,HIGH);
digitalWrite(MOTO_7_PIN_2,LOW);
delay(delay_flash);
digitalWrite(MOTO_7_PIN_1,HIGH);
digitalWrite(MOTO_7_PIN_2,LOW);
//pinMode(LED_BUILTIN,OUTPUT);
//digitalWrite(LED_BUILTIN,HIGH);
}

void motor7_left(){
digitalWrite(MOTO_7_PIN_1,LOW);
digitalWrite(MOTO_7_PIN_2,HIGH);
delay(delay_flash);
digitalWrite(MOTO_7_PIN_1,LOW);
digitalWrite(MOTO_7_PIN_2,HIGH);
//pinMode(LED_BUILTIN,OUTPUT);
//digitalWrite(LED_BUILTIN,LOW);
}

void stop_car(){
digitalWrite(MOTO_1_PIN_1,LOW);
digitalWrite(MOTO_1_PIN_2,LOW);
digitalWrite(MOTO_2_PIN_1,LOW);
digitalWrite(MOTO_2_PIN_2,LOW);
digitalWrite(MOTO_3_PIN_1,LOW);
digitalWrite(MOTO_3_PIN_2,LOW);
digitalWrite(MOTO_4_PIN_1,LOW);
digitalWrite(MOTO_4_PIN_2,LOW);
digitalWrite(MOTO_5_PIN_1,LOW);
digitalWrite(MOTO_5_PIN_2,LOW);
digitalWrite(MOTO_6_PIN_1,LOW);
digitalWrite(MOTO_6_PIN_2,LOW);
digitalWrite(MOTO_7_PIN_1,LOW);
digitalWrite(MOTO_7_PIN_2,LOW);
digitalWrite(MOTO_8_PIN_1,LOW);
digitalWrite(MOTO_8_PIN_2,LOW);
}

void control_car(const std_msgs::UInt16 &msg)
{
switch(msg.data)
{
case 0:stop_car();break;
case 1:forward_car();break;
case 2:backward_car();break;
case 3:left_car();break;
case 4:right_car();break;
case 5:motor5_right();break;
case 6:motor5_left();break;
case 7:motor6_right();break;
case 8:motor6_left();break;
case 9:motor7_right();break;
case 10:motor7_left();break;
default:stop_car();
}
}

ros::Subscriber<std_msgs::UInt16> sub("/command", &control_car);

void setup() {
Serial.begin(115200);
setupWiFi();
init_motorPin();
nh.getHardware()->setConnection(server);
nh.initNode();
nh.advertise(chatter);
nh.subscribe(sub);
}

void loop() {

//str_msg.data=hello;
//chatter.publish( &str_msg );
nh.spinOnce();

}

4.效果展示


esp32与ros局域网话题通信IO口控制


参考链接

1.查找input_event为键盘事件时的键值:

2.input_event结构体事件详解(keyvalue)

3.键盘事件监听

4.文件读取

5.termios库对终端的设置

Linux中不显示输入的字符的实现-hyfeng18-ChinaUnix博客