diff options
Diffstat (limited to 'serial/serial.c')
-rw-r--r-- | serial/serial.c | 203 |
1 files changed, 110 insertions, 93 deletions
diff --git a/serial/serial.c b/serial/serial.c index db45fac..57b432c 100644 --- a/serial/serial.c +++ b/serial/serial.c | |||
@@ -1,130 +1,147 @@ | |||
1 | #include "path_ctrl_t.h" | 1 | #include "serial.h" |
2 | #include <errno.h> | ||
3 | #include <fcntl.h> | ||
4 | #include <stdbool.h> | ||
5 | #include <stdio.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | #include <termios.h> | ||
9 | #include <unistd.h> | ||
10 | 2 | ||
11 | typedef unsigned char byte; | 3 | lcm_t *lcm; |
12 | #define MAX_BUFFER_SIZE 1024 | ||
13 | #define DEFAULT_SPEED 0x15 | ||
14 | 4 | ||
15 | int fd; // 轮子的串口文件描述符 | 5 | int curStatus = -1, curSpeed = 0; // 这里的速度指百分比速度 |
16 | char portname[50] = "/dev/ttyUSB0"; // 串口设备名 | 6 | double curOmega; |
17 | char clientIP[20] = ""; | 7 | // 临界区数据 |
18 | struct termios tty; | 8 | pthread_mutex_t curPoseMutex; |
19 | 9 | clock_t lastTime; | |
20 | bool whellInit(); | 10 | double curPose[3] = {0, 0, 0}; |
21 | bool wheelSend(byte a, byte a_v, byte b, byte b_v); | ||
22 | void speedControl(byte status, byte speed); | ||
23 | void parseCmd(const lcm_recv_buf_t *rbuf, const char *channel, | ||
24 | const path_ctrl_t *msg, void *userdata); | ||
25 | 11 | ||
26 | int main() { | 12 | int main() { |
27 | if (!whellInit()) { | 13 | if (!whellInit()) { |
28 | goto err; | 14 | goto err; |
29 | } | 15 | } |
30 | lcm_t *path_lcm = lcm_create(NULL); | 16 | lcm = lcm_create(NULL); |
31 | if (!path_lcm) { | 17 | if (!lcm) { |
32 | fprintf(stderr, "Failed to create LCM\n"); | 18 | fprintf(stderr, "Failed to create LCM\n"); |
33 | goto err; | 19 | goto err; |
34 | } | 20 | } |
35 | path_ctrl_t cmd; | 21 | |
36 | path_ctrl_t_subscribe(path_lcm, "wheel_ctrl", parseCmd, &cmd); | 22 | // 订阅来自手机端的轮控消息 |
23 | path_ctrl_t_subscribe(lcm, "wheel_ctrl", parseCmd, NULL); | ||
24 | // 订阅来自算法模块的路径规划消息 | ||
25 | path_t_subscribe(lcm, "PATH", parsePath, NULL); | ||
26 | // 来自算法模块的当前位置信息 | ||
27 | pthread_mutex_init(&curPoseMutex, NULL); | ||
28 | pose_t_subscribe(lcm, "CURRENTPOSE", setCurPose, NULL); | ||
29 | // 新线程,定时发送当前位置信息 | ||
30 | pthread_t thread; | ||
31 | if (pthread_create(&thread, NULL, sendCurPose, NULL) != 0) { | ||
32 | fprintf(stderr, "Error: Failed to create thread\n"); | ||
33 | goto err; | ||
34 | } | ||
37 | 35 | ||
38 | while (true) { | 36 | while (true) { |
39 | lcm_handle(path_lcm); | 37 | lcm_handle(lcm); |
40 | } | 38 | } |
41 | 39 | ||
42 | err: | 40 | err: |
43 | close(fd); | 41 | // close(fd); |
44 | return 0; | 42 | return 0; |
45 | } | 43 | } |
46 | 44 | ||
47 | bool whellInit() { | ||
48 | // 打开串口 | ||
49 | fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); | ||
50 | if (fd < 0) { | ||
51 | fprintf(stderr, "Error opening %s: %s\n", portname, strerror(errno)); | ||
52 | return false; | ||
53 | } | ||
54 | |||
55 | // 设置串口参数 | ||
56 | memset(&tty, 0, sizeof tty); | ||
57 | if (tcgetattr(fd, &tty) != 0) { | ||
58 | fprintf(stderr, "Error from tcgetattr: %s\n", strerror(errno)); | ||
59 | return false; | ||
60 | } | ||
61 | |||
62 | cfsetospeed(&tty, B115200); // 设置输出波特率为115200 | ||
63 | cfsetispeed(&tty, B115200); // 设置输入波特率为115200 | ||
64 | |||
65 | tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars | ||
66 | tty.c_iflag &= ~IGNBRK; // ignore break signal | ||
67 | tty.c_lflag = 0; // no signaling chars, no echo, | ||
68 | // no canonical processing | ||
69 | tty.c_oflag = 0; // no remapping, no delays | ||
70 | tty.c_cc[VMIN] = 0; // read doesn't block | ||
71 | tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout | ||
72 | |||
73 | tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl | ||
74 | tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls, | ||
75 | // enable reading | ||
76 | tty.c_cflag &= ~(PARENB | PARODD); // shut off parity | ||
77 | tty.c_cflag |= 0; | ||
78 | tty.c_cflag &= ~CSTOPB; | ||
79 | tty.c_cflag &= ~CRTSCTS; | ||
80 | |||
81 | if (tcsetattr(fd, TCSANOW, &tty) != 0) { | ||
82 | fprintf(stderr, "Error from tcsetattr: %s\n", strerror(errno)); | ||
83 | return false; | ||
84 | } | ||
85 | return true; | ||
86 | } | ||
87 | |||
88 | bool wheelSend(byte a, byte a_v, byte b, byte b_v) { | ||
89 | unsigned char data[7] = {0x53, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
90 | byte checksum = 0; | ||
91 | data[2] = a; | ||
92 | data[3] = a_v; | ||
93 | data[4] = b; | ||
94 | data[5] = b_v; | ||
95 | |||
96 | for (int i = 0; i < 6; i++) { | ||
97 | checksum ^= data[i]; | ||
98 | } | ||
99 | data[6] = checksum; | ||
100 | |||
101 | // 发送数据 | ||
102 | if (write(fd, data, 7) != 7) { | ||
103 | fprintf(stderr, "Failed to write to the serial port\n"); | ||
104 | return false; | ||
105 | } | ||
106 | |||
107 | printf("Data %02X %02X %02X %02X %02X %02X %02X wheelSend successfully!\n", | ||
108 | data[0], data[1], data[2], data[3], data[4], data[5], data[6]); | ||
109 | return true; | ||
110 | } | ||
111 | |||
112 | void parseCmd(const lcm_recv_buf_t *rbuf, const char *channel, | 45 | void parseCmd(const lcm_recv_buf_t *rbuf, const char *channel, |
113 | const path_ctrl_t *msg, void *userdata) { | 46 | const path_ctrl_t *msg, void *userdata) { |
114 | byte status = msg->cmd, speed = msg->speed; | 47 | byte status = msg->cmd, speed = msg->speed; |
48 | if (curStatus == status && curSpeed == speed) { | ||
49 | return; | ||
50 | } | ||
51 | |||
52 | // 状态改变,计算新的位置 | ||
53 | renewCurPose(); | ||
54 | |||
55 | // 下发新的指令 | ||
115 | switch (status) { | 56 | switch (status) { |
116 | case 1: | 57 | case 1: |
117 | wheelSend(0x01, speed, 0x01, speed); | 58 | wheelSend(0x01, speed, 0x01, speed); |
59 | curSpeed = speed; | ||
60 | curOmega = 0; | ||
118 | break; | 61 | break; |
119 | case 2: | 62 | case 2: |
120 | wheelSend(0x02, DEFAULT_SPEED, 0x01, DEFAULT_SPEED); | 63 | wheelSend(0x02, DEFAULT_SPEED, 0x01, DEFAULT_SPEED); |
64 | curOmega = (double)DEFAULT_SPEED * FULLSPEED / 100 / RADIUS; | ||
65 | curSpeed = 0; | ||
121 | break; | 66 | break; |
122 | case 3: | 67 | case 3: |
123 | wheelSend(0x01, DEFAULT_SPEED, 0x02, DEFAULT_SPEED); | 68 | wheelSend(0x01, DEFAULT_SPEED, 0x02, DEFAULT_SPEED); |
69 | curOmega = (double)-DEFAULT_SPEED * FULLSPEED / 100 / RADIUS; | ||
70 | curSpeed = 0; | ||
124 | break; | 71 | break; |
125 | case 0: | 72 | case 0: |
126 | default: | 73 | default: |
127 | wheelSend(0x00, 0x00, 0x00, 0x00); | 74 | wheelSend(0x00, 0x00, 0x00, 0x00); |
75 | curOmega = 0; | ||
76 | curSpeed = 0; | ||
128 | break; | 77 | break; |
129 | } | 78 | } |
79 | // 更新状态 | ||
80 | curStatus = status; | ||
81 | } | ||
82 | |||
83 | void parsePath(const lcm_recv_buf_t *rbuf, const char *channel, | ||
84 | const path_t *msg, void *userdata) { | ||
85 | int16_t length = msg->length; | ||
86 | double v, w; | ||
87 | int8_t vWheels[2]; | ||
88 | int8_t bWheels[2]; | ||
89 | if (length <= 0) { | ||
90 | fprintf(stderr, "Error: Invalid path\n"); | ||
91 | return; | ||
92 | } | ||
93 | v = msg->xyr[0][0]; | ||
94 | w = msg->xyr[0][1]; | ||
95 | if (fabs(v) <= 0.01 && fabs(w) <= 0.01) { | ||
96 | wheelSend(0x00, 0x00, 0x00, 0x00); | ||
97 | renewCurPose(); | ||
98 | curSpeed = 0; | ||
99 | curOmega = 0; | ||
100 | } else { | ||
101 | vWheels[0] = (int8_t)((double)(v - w * RADIUS) / FULLSPEED * 100); | ||
102 | vWheels[1] = (int8_t)((double)(v + w * RADIUS) / FULLSPEED * 100); | ||
103 | bWheels[0] = vWheels[0] > 0 ? 0x01 : 0x02; | ||
104 | bWheels[1] = vWheels[1] > 0 ? 0x01 : 0x02; | ||
105 | wheelSend(bWheels[0], fabs(vWheels[0]), bWheels[1], fabs(vWheels[1])); | ||
106 | renewCurPose(); | ||
107 | curSpeed = (int8_t)((double)v / FULLSPEED * 100); | ||
108 | curOmega = (int8_t)w; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | void setCurPose(const lcm_recv_buf_t *rbuf, const char *channel, | ||
113 | const pose_t *msg, void *userdata) { | ||
114 | pthread_mutex_lock(&curPoseMutex); | ||
115 | curPose[0] = msg->pos[0]; | ||
116 | curPose[1] = msg->pos[1]; | ||
117 | curPose[2] = msg->pos[2]; | ||
118 | lastTime = clock(); | ||
119 | pthread_mutex_unlock(&curPoseMutex); | ||
120 | } | ||
121 | |||
122 | void sendCurPose() { | ||
123 | pose_t pose; | ||
124 | while (true) { | ||
125 | renewCurPose(); | ||
126 | pthread_mutex_lock(&curPoseMutex); | ||
127 | pose.pos[0] = curPose[0]; | ||
128 | pose.pos[1] = curPose[1]; | ||
129 | pose.pos[2] = curPose[2]; | ||
130 | pthread_mutex_unlock(&curPoseMutex); | ||
131 | pose_t_publish(lcm, "POSE", &pose); | ||
132 | usleep(16); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | void renewCurPose() { | ||
137 | clock_t curTime = clock(); | ||
138 | double dt = (double)(curTime - lastTime) / CLOCKS_PER_SEC; | ||
139 | double speed = (double)curSpeed * FULLSPEED / 100; | ||
140 | |||
141 | pthread_mutex_lock(&curPoseMutex); | ||
142 | curPose[0] += speed * cos(curPose[2]) * dt; | ||
143 | curPose[1] += speed * sin(curPose[2]) * dt; | ||
144 | curPose[2] += curOmega * dt; | ||
145 | lastTime = curTime; | ||
146 | pthread_mutex_unlock(&curPoseMutex); | ||
130 | } \ No newline at end of file | 147 | } \ No newline at end of file |