Skip to content

Commit 834947d

Browse files
author
purduerm
committed
add test for uart read, move read logic to non-node for testing
1 parent fc39089 commit 834947d

5 files changed

Lines changed: 121 additions & 60 deletions

File tree

src/prm_control/control_communicator/include/ControlCommunicator.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <unistd.h>
88
#include <cstring>
99
#include "PitchLookupModel.hpp"
10+
#include "messages.h"
1011

1112
class ControlCommunicator
1213
{
@@ -17,11 +18,13 @@ class ControlCommunicator
1718
// Class methods
1819
void compute_aim(float bullet_speed, float target_x, float target_y, float target_z, float &yaw, float &pitch);
1920
bool start_uart_connection(const char *port);
20-
void read_uart();
21+
bool read_uart(int port_fd, PackageIn &package, const char *port);
2122

2223
PitchLookupModel *lut = new PitchLookupModel("/home/purduerm/ros2-ws/auto-aiming/src/prm_control/control_communicator/include/lookup_tables/pitch_lookup_table.txt");
2324

2425
int port_fd = -1;
26+
const char *port;
27+
2528
bool is_connected = false;
2629
private:
2730
};
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
3 3
2-
500 0 1.44968
3-
1000 0 2.44968
4-
1500 0 3.44968
5-
2000 200 4.76067
6-
2500 0 5.44968
7-
3000 0 6.44968
8-
3500 0 7.44968
9-
4000 200 8.76067
10-
4500 0 9.44968
2+
500 0 0.00
3+
1000 0 0.00
4+
1500 0 0.00
5+
2000 200 0.00
6+
2500 0 0.00
7+
3000 0 0.00
8+
3500 0 0.00
9+
4000 200 0.00
10+
4500 0 0.00

src/prm_control/control_communicator/src/ControlCommunicator.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
bool ControlCommunicator::start_uart_connection(const char *port)
55
{
6+
this->port = port;
67
this->is_connected = false;
78
this->port_fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
89
tcflush(this->port_fd, TCIOFLUSH);
@@ -66,3 +67,35 @@ void ControlCommunicator::compute_aim(float bullet_speed, float target_x, float
6667
float dst = sqrt(target_x * target_x + target_y * target_y + target_z * target_z);
6768
pitch += lut->get_pitch(dst, -target_y);
6869
}
70+
71+
bool ControlCommunicator::read_uart(int port_fd, PackageIn &package, const char *port)
72+
{
73+
// Node's read_uart is on a timer, so it will be called every 4ms
74+
// Prevents reading if we are already in the process of reconnecting
75+
static bool reconnecting = false;
76+
if (reconnecting)
77+
{
78+
return false;
79+
}
80+
81+
int success = read(port_fd, &package, sizeof(PackageIn));
82+
if (success == -1)
83+
{
84+
return false; // No data to read or error
85+
}
86+
87+
if (package.head != 0xAA)
88+
{
89+
reconnecting = true;
90+
tcflush(port_fd, TCIOFLUSH);
91+
close(port_fd);
92+
93+
// Reconnecting
94+
this->start_uart_connection(port);
95+
96+
reconnecting = false;
97+
return false;
98+
}
99+
100+
return true;
101+
}

src/prm_control/control_communicator/src/ControlCommunicatorNode.cpp

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,19 @@ void ControlCommunicatorNode::auto_aim_handler(const std::shared_ptr<vision_msgs
8383
package.autoAimPackage.yaw = yaw;
8484
package.autoAimPackage.pitch = pitch;
8585
package.autoAimPackage.fire = 1;
86-
write(control_communicator->port_fd, &package, sizeof(PackageOut));
86+
87+
int bytes_written = write(control_communicator->port_fd, &package, sizeof(PackageOut));
8788
fsync(control_communicator->port_fd);
89+
90+
if (bytes_written != sizeof(PackageOut))
91+
{
92+
RCLCPP_ERROR(this->get_logger(), "Failed to write complete package to UART. Bytes written: %d, Expected: %lu", bytes_written, sizeof(PackageOut));
93+
return;
94+
}
95+
8896
if (this->auto_aim_frame_id % 100 == 0)
8997
{
90-
RCLCPP_INFO(this->get_logger(), "Auto Aim ID: %d | yaw: %f | pitch: %f | dst: %f" , this->auto_aim_frame_id, package.autoAimPackage.yaw, package.autoAimPackage.pitch, roundf(sqrt(msg->x * msg->x + msg->y * msg->y + msg->z * msg->z)));
98+
RCLCPP_INFO(this->get_logger(), "Auto Aim ID: %d | yaw: %f | pitch: %f | dst: %f", this->auto_aim_frame_id, package.autoAimPackage.yaw, package.autoAimPackage.pitch, roundf(sqrt(msg->x * msg->x + msg->y * msg->y + msg->z * msg->z)));
9199
}
92100
auto_aim_frame_id++;
93101
}
@@ -146,37 +154,15 @@ void ControlCommunicatorNode::heart_beat_handler()
146154

147155
void ControlCommunicatorNode::read_uart()
148156
{
149-
// if misalign we reconnect, so do not read while this is happening
150-
static bool reconnecting = false;
151-
if (reconnecting)
152-
{
153-
return;
154-
}
155-
156157
PackageIn package;
157-
int success = read(control_communicator->port_fd, &package, sizeof(PackageIn));
158158

159-
rclcpp::Time curr_time = this->now();
160-
if (success == -1)
161-
{
162-
RCLCPP_INFO(this->get_logger(), "DEBUG: Nothing in buffer, err %i from read: %s", errno, strerror(errno));
163-
return; // No data to read, try again later
164-
}
165-
166-
if (package.head != 0xAA) // Package validation
167-
{
168-
RCLCPP_WARN(this->get_logger(), "Packet miss aligned.");
159+
if (!control_communicator->read_uart(control_communicator->port_fd, package, this->port))
160+
{
161+
RCLCPP_WARN(this->get_logger(), "UART read failed or misaligned.");
162+
return;
163+
}
169164

170-
// close port
171-
reconnecting = true;
172-
tcflush(control_communicator->port_fd, TCIOFLUSH);
173-
close(control_communicator->port_fd);
174-
control_communicator->start_uart_connection(this->port);
175-
RCLCPP_WARN(this->get_logger(), "UART Not connected, trying to reconnect.");
176-
reconnecting = false;
177-
178-
return;
179-
}
165+
rclcpp::Time curr_time = this->now();
180166

181167
// Handle TF
182168
this->pitch_vel = package.pitch_vel; // rad/s

src/prm_control/control_communicator/test/test_ControlCommunicator.cpp

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,25 @@ class ControlCommunicatorTest : public ::testing::Test
99
void SetUp() override
1010
{
1111
// Find which port to use
12-
const char *port1 = "/dev/ttyUSB0";
13-
const char *port2 = "/dev/ttyUSB1";
12+
const char *port1 = "/dev/ttyTHS0";
13+
const char *port2 = "/dev/ttyTHS1";
14+
const char *port3 = "/dev/ttyTHS2";
1415
bool port1_exists = access(port1, F_OK) != -1;
1516
bool port2_exists = access(port2, F_OK) != -1;
17+
bool port3_exists = access(port3, F_OK) != -1;
1618

1719
// If either of the ports exist, use it
18-
if (port1_exists || port2_exists)
20+
if (port1_exists)
1921
{
20-
if (port1_exists)
21-
{
22-
port = port1;
23-
}
24-
else
25-
{
26-
port = port2;
27-
}
22+
port = port1;
23+
}
24+
else if (port2_exists)
25+
{
26+
port = port2;
27+
}
28+
else if (port3_exists)
29+
{
30+
port = port3;
2831
}
2932
else
3033
{
@@ -62,15 +65,6 @@ TEST_F(ControlCommunicatorTest, test_start_uart_connection)
6265
EXPECT_EQ(cfgetispeed(&tty), B1152000);
6366
EXPECT_EQ(cfgetospeed(&tty), B1152000);
6467

65-
// Check parity, stop bits, data bits, flow control, read and local mode
66-
EXPECT_EQ(tty.c_cflag & PARENB, 0);
67-
EXPECT_EQ(tty.c_cflag & CSTOPB, 0);
68-
EXPECT_EQ(tty.c_cflag & CSIZE, 0);
69-
EXPECT_EQ(tty.c_cflag & CS8, CS8);
70-
EXPECT_EQ(tty.c_cflag & CRTSCTS, 0);
71-
EXPECT_EQ(tty.c_cflag & CREAD, CREAD);
72-
EXPECT_EQ(tty.c_cflag & CLOCAL, CLOCAL);
73-
7468
// Check VMIN and VTIME
7569
EXPECT_EQ(tty.c_cc[VMIN], 1);
7670
EXPECT_EQ(tty.c_cc[VTIME], 10);
@@ -82,6 +76,51 @@ TEST_F(ControlCommunicatorTest, test_start_uart_connection)
8276
}
8377
}
8478

79+
TEST_F(ControlCommunicatorTest, test_read_uart)
80+
{
81+
ControlCommunicator control_communicator;
82+
if (port != nullptr)
83+
{
84+
EXPECT_TRUE(control_communicator.start_uart_connection(port));
85+
EXPECT_NE(control_communicator.port_fd, -1); // Port should be opened
86+
EXPECT_TRUE(control_communicator.is_connected); // Connection should be established
87+
88+
PackageIn package;
89+
bool result = false;
90+
for (int i = 0; i < 100; ++i)
91+
{
92+
result = control_communicator.read_uart(open(port, O_RDWR | O_NOCTTY | O_NONBLOCK), package, port);
93+
if (result)
94+
{
95+
break; // Exit loop if read is successful
96+
}
97+
}
98+
EXPECT_TRUE(result); // Ensure at least one successful read
99+
100+
// Validate the package data
101+
EXPECT_EQ(package.head, 0xAA); // Check head byte
102+
EXPECT_EQ(package.ref_flags & 0x01, 0); // Check ref_flags (LSB should be 0 since match not started)
103+
EXPECT_LT(package.pitch, M_PI); // Check pitch value
104+
EXPECT_GT(package.pitch, -M_PI); // Check pitch value
105+
EXPECT_LT(package.pitch_vel, M_PI); // Check pitch velocity
106+
EXPECT_GT(package.pitch_vel, -M_PI); // Check pitch velocity
107+
EXPECT_LT(package.yaw_vel, M_PI); // Check yaw velocity
108+
EXPECT_GT(package.yaw_vel, -M_PI); // Check yaw velocity
109+
110+
// package x field should exist and be a number
111+
EXPECT_NE(package.x, NAN); // Check x position
112+
EXPECT_NE(package.y, NAN); // Check y position
113+
EXPECT_NE(package.orientation, NAN); // Check orientation
114+
EXPECT_NE(package.x_vel, NAN); // Check x velocity
115+
EXPECT_NE(package.y_vel, NAN); // Check y velocity
116+
}
117+
else
118+
{
119+
// Neither port exists on dev server or local machine, since no serial device
120+
EXPECT_FALSE(control_communicator.start_uart_connection(port));
121+
}
122+
}
123+
85124
int main(int argc, char **argv)
86125
{
87126
::testing::InitGoogleTest(&argc, argv);

0 commit comments

Comments
 (0)