rc.cpp
Go to the documentation of this file.
1 /*
2  * Clover mobile remote control backend
3  * Send ManualControl messages through UDP
4  * 'latched_state' topic
5  *
6  * Copyright (C) 2019 Copter Express Technologies
7  *
8  * Author: Oleg Kalachev <okalachev@gmail.com>
9  *
10  * Distributed under MIT License (available at https://opensource.org/licenses/MIT).
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13  */
14 
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <errno.h>
18 #include <thread>
19 #include "ros/ros.h"
20 #include "std_msgs/String.h"
21 #include "mavros_msgs/State.h"
22 #include "mavros_msgs/ManualControl.h"
23 #include "mavros_msgs/Mavlink.h"
24 
26 {
27  int16_t x, y, z, r;
28 } __attribute__((packed));
29 
30 class RC
31 {
32 public:
33  RC():
34  nh(),
35  nh_priv("~")
36  {
37  bool use_fake_gcs = nh_priv.param("use_fake_gcs", true);
38  // Create socket thread
39  std::thread t(&RC::socketThread, this);
40  t.detach();
41 
42  if (use_fake_gcs) {
43  std::thread gcst(&RC::fakeGCSThread, this);
44  gcst.detach();
45  }
46 
47  initLatchedState();
48  }
49 
50 private:
55  ros::Time last_manual_control{0};
56  mavros_msgs::StateConstPtr state_msg;
57 
58  void handleState(const mavros_msgs::StateConstPtr& state)
59  {
60  state_timeout_timer.setPeriod(ros::Duration(3), true);
61  state_timeout_timer.start();
62 
63  if (!state_msg ||
64  state->connected != state_msg->connected ||
65  state->mode != state_msg->mode ||
66  state->armed != state_msg->armed) {
67  state_msg = state;
68  state_pub.publish(state_msg);
69  }
70  }
71 
73  {
74  ROS_INFO("State timeout");
75  mavros_msgs::State unknown_state;
76  state_pub.publish(unknown_state);
77  state_msg = nullptr;
78  }
79 
81  {
82  state_sub = nh.subscribe("mavros/state", 1, &RC::handleState, this);
83  state_pub = nh.advertise<mavros_msgs::State>("state_latched", 1, true);
84  state_timeout_timer = nh.createTimer(ros::Duration(0), &RC::stateTimedOut, this, true, false);
85 
86  // Publish initial state
87  mavros_msgs::State unknown_state;
88  state_pub.publish(unknown_state);
89  }
90 
92  {
93  // Awful workaround for fixing PX4 not sending STATUSTEXTs
94  // if there is no GCS hearbeats.
95  // TODO: use timer
96  // TODO: remove, when PX4 get this fixed.
97  ros::Publisher mavlink_pub = nh.advertise<mavros_msgs::Mavlink>("mavlink/to", 1);
98 
99  // HEARTBEAT from GCS message
100  mavros_msgs::Mavlink hb;
101  hb.framing_status = mavros_msgs::Mavlink::FRAMING_OK;
102  hb.magic = mavros_msgs::Mavlink::MAVLINK_V20;
103  hb.len = 9;
104  hb.incompat_flags = 0;
105  hb.compat_flags = 0;
106  hb.seq = 0;
107  hb.sysid = 255;
108  hb.compid = 0;
109  hb.checksum = 26460;
110  hb.payload64.push_back(342282393542983680);
111  hb.payload64.push_back(3);
112 
113  ros::Rate rate(1);
114  while (ros::ok()) {
115  if (ros::Time::now() - last_manual_control < ros::Duration(8)) {
116  mavlink_pub.publish(hb);
117  }
118  rate.sleep();
119  }
120  }
121 
122  int createSocket(int port)
123  {
124  int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
125 
126  sockaddr_in sin;
127  sin.sin_family = AF_INET;
128  sin.sin_addr.s_addr = htonl(INADDR_ANY);
129  sin.sin_port = htons(port);
130 
131  if (bind(sockfd, (sockaddr *)&sin, sizeof(sin)) < 0) {
132  ROS_FATAL("socket bind error: %s", strerror(errno));
133  close(sockfd);
134  ros::shutdown();
135  }
136 
137  return sockfd;
138  }
139 
141  {
142  int port;
143  nh_priv.param("port", port, 35602);
144  int sockfd = createSocket(port);
145 
146  char buff[9999];
147 
148  ros::Publisher manual_control_pub = nh.advertise<mavros_msgs::ManualControl>("mavros/manual_control/send", 1);
149  mavros_msgs::ManualControl manual_control_msg;
150 
151  sockaddr_in client_addr;
152  socklen_t client_addr_size = sizeof(client_addr);
153 
154  ROS_INFO("UDP RC initialized on port %d", port);
155 
156  while (true) {
157  // read next UDP packet
158  int bsize = recvfrom(sockfd, &buff[0], sizeof(buff) - 1, 0, (sockaddr *) &client_addr, &client_addr_size);
159 
160  if (bsize < 0) {
161  ROS_ERROR("recvfrom() error: %s", strerror(errno));
162  } else if (bsize != sizeof(ControlMessage)) {
163  ROS_ERROR_THROTTLE(30, "Wrong UDP packet size: %d", bsize);
164  }
165 
166  // unpack message
167  // warning: ignore endianness, so the code is platform-dependent
168  ControlMessage *msg = (ControlMessage *)buff;
169 
170  manual_control_msg.x = msg->x;
171  manual_control_msg.y = msg->y;
172  manual_control_msg.z = msg->z;
173  manual_control_msg.r = msg->r;
174  manual_control_pub.publish(manual_control_msg);
175 
176  last_manual_control = ros::Time::now();
177  }
178  }
179 };
180 
181 int main(int argc, char **argv)
182 {
183  ros::init(argc, argv, "rc");
184  RC rc;
185  ros::spin();
186 }
ros::Publisher state_pub
Definition: rc.cpp:53
msg
mavros_msgs::StateConstPtr state_msg
Definition: rc.cpp:56
led_msgs::LEDStateArray state
Definition: led.cpp:34
#define ROS_FATAL(...)
void initLatchedState()
Definition: rc.cpp:80
ros::NodeHandle nh
Definition: rc.cpp:30
int16_t z
Definition: rc.cpp:27
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void setPeriod(const Duration &period, bool reset=true)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void start()
void handleState(const mavros_msgs::StateConstPtr &state)
Definition: rc.cpp:58
void close() override
class RC __attribute__
int16_t x
Definition: rc.cpp:27
void fakeGCSThread()
Definition: rc.cpp:91
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void publish(const boost::shared_ptr< M > &message) const
ros::Publisher mavlink_pub
#define ROS_INFO(...)
#define ROS_ERROR_THROTTLE(period,...)
ROSCPP_DECL bool ok()
port
int createSocket(int port)
Definition: rc.cpp:122
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ROSCPP_DECL void spin()
int16_t y
Definition: rc.cpp:27
bool sleep()
int main(int argc, char **argv)
Definition: rc.cpp:181
void stateTimedOut(const ros::TimerEvent &)
Definition: rc.cpp:72
ros::Timer state_timeout_timer
Definition: rc.cpp:54
void socketThread()
Definition: rc.cpp:140
boost::asio::ip::tcp::socket socket
static Time now()
ROSCPP_DECL void shutdown()
RC()
Definition: rc.cpp:33
ros::NodeHandle nh_priv
Definition: rc.cpp:51
int16_t r
Definition: rc.cpp:27
#define ROS_ERROR(...)
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
ros::Subscriber state_sub
Definition: rc.cpp:52


clover
Author(s): Oleg Kalachev , Artem Smirnov
autogenerated on Mon Feb 28 2022 22:08:29