innok_heros_can_driver.cpp
Go to the documentation of this file.
00001 /* Copyright 2017 Innok Robotics GmbH */
00002 
00003 #include <stdio.h>
00004 #include <string.h>
00005 #include <fcntl.h>
00006 #include <sys/ioctl.h>
00007 #include <net/if.h>
00008 #include <linux/can.h>
00009 #include <linux/can/raw.h>
00010 #include <ros/ros.h>
00011 #include <geometry_msgs/Twist.h>
00012 #include <geometry_msgs/Point.h>
00013 #include <geometry_msgs/Quaternion.h>
00014 #include <nav_msgs/Odometry.h>
00015 #include <sensor_msgs/Joy.h>
00016 #include <std_msgs/Float32.h>
00017 #include <tf/transform_broadcaster.h>
00018 #include <boost/thread/thread.hpp>
00019 #include <boost/thread/mutex.hpp>
00020 
00021 
00022 // Prototypes
00023 void publishJoyMsg();
00024 void publishOdomMsg();
00025 void publishVoltageMsg();
00026 
00027 // Variables
00028 int can_socket;
00029 
00030 double battery_voltage = 0;
00031 double odom_orientation = 0;
00032 double odom_pos_x = 0;
00033 double odom_pos_y = 0;
00034 
00035 uint8_t remote_buttons[8];
00036 uint8_t remote_analog[8];
00037 
00038 ros::Publisher publisherOdom;
00039 ros::Publisher publisherJoy;
00040 ros::Publisher publisherVoltage;
00041 
00042 boost::mutex ros_mutex;
00043 bool can_running = false;
00044 
00045 int can_open(const char * device)
00046 {
00047     struct ifreq ifr;
00048     struct sockaddr_can addr;
00049     /* open socket */
00050     can_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
00051     if(can_socket < 0)
00052     {
00053         return (-1);
00054     }
00055     addr.can_family = AF_CAN;
00056     strcpy(ifr.ifr_name, device);
00057     
00058     if (ioctl(can_socket, SIOCGIFINDEX, &ifr) < 0)
00059     {
00060         return (-2);
00061     }
00062     addr.can_ifindex = ifr.ifr_ifindex;
00063     //fcntl(can_socket, F_SETFL, O_NONBLOCK);
00064 
00065     
00066     if (bind(can_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
00067     {
00068         return (-3);
00069     }
00070     
00071     struct timeval tv;
00072     tv.tv_sec = 1;  // 1 second timeout 
00073     tv.tv_usec = 0;  // Not init'ing this can cause strange errors
00074     setsockopt(can_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));
00075     
00076     return 0;
00077 }
00078 
00079 int can_send_frame(struct can_frame * frame)
00080 {
00081     int retval;
00082     retval = write(can_socket, frame, sizeof(struct can_frame));
00083     if (retval != sizeof(struct can_frame))
00084     {
00085         return (-1);
00086     }
00087     else
00088     {
00089         return (0);
00090     }
00091 }
00092 
00093 int can_send_cmd_vel(double speed, double yawspeed, int modestate = 3)
00094 {
00095     struct can_frame msg_send;
00096     
00097     msg_send.can_id = 200;
00098     msg_send.can_dlc = 5;
00099     
00100     int int_speed = speed * 100;
00101     int int_yaw = yawspeed * 100;
00102     msg_send.data[0] = int_speed;
00103     msg_send.data[1] = int_speed >> 8;
00104     msg_send.data[2] = int_yaw;
00105     msg_send.data[3] = int_yaw >> 8;
00106     msg_send.data[4] = modestate;
00107     
00108     can_send_frame(&msg_send);
00109 }
00110     
00111 
00112 void can_read_frames()
00113 {
00114     struct can_frame frame_rd;
00115     while(read(can_socket, &frame_rd, sizeof(struct can_frame))>0)
00116     {
00117         // Remote Control Values
00118         if (frame_rd.can_id == 0x1E4)       
00119         {
00120             for (int i = 0; i < 8; i++)
00121                 remote_analog[i] = frame_rd.data[i];
00122         }
00123         else if(frame_rd.can_id == 0x2E4)        // Switches
00124         {
00125             for (int i = 0; i < 8; i++)
00126                 remote_buttons[i] = frame_rd.data[i];
00127             publishJoyMsg();
00128         }
00129         else if (frame_rd.can_id == 235)
00130         {
00131             battery_voltage = (frame_rd.data[1]|(frame_rd.data[2]<<8))*0.01;
00132             publishVoltageMsg();
00133         }
00134         else if (frame_rd.can_id == 236)
00135         {
00136             odom_pos_x = (frame_rd.data[0]|(frame_rd.data[1]<<8)|(frame_rd.data[2]<<16)|(frame_rd.data[3]<<24))*0.001;
00137             odom_pos_y = (frame_rd.data[4]|(frame_rd.data[5]<<8)|(frame_rd.data[6]<<16)|(frame_rd.data[7]<<24))*0.001;
00138         }
00139         else if (frame_rd.can_id == 237)
00140         {
00141             odom_orientation = (frame_rd.data[0]|(frame_rd.data[1]<<8)|(frame_rd.data[2]<<16)|(frame_rd.data[3]<<24))*0.001;
00142             publishOdomMsg();
00143         }
00144     }
00145 }
00146 
00147 void publishOdomMsg()
00148 {
00149     static tf::TransformBroadcaster tf_br;
00150 
00151     geometry_msgs::Quaternion odom_quaternion = tf::createQuaternionMsgFromYaw(odom_orientation);
00152     
00153     nav_msgs::Odometry odom_msg;
00154     odom_msg.header.stamp = ros::Time::now();
00155     odom_msg.header.frame_id = "/odom";
00156     odom_msg.child_frame_id = "/base_link";
00157     odom_msg.pose.pose.position.x = odom_pos_x;
00158     odom_msg.pose.pose.position.y = odom_pos_y;
00159     odom_msg.pose.pose.orientation = odom_quaternion;
00160     
00161     
00162     double odom_covariance[] = {0.1,    0,      0,      0,      0,      0,
00163                                 0,      0.1,    0,      0,      0,      0,
00164                                 0,      0,      9999.0, 0,      0,      0,
00165                                 0,      0,      0,      0.6,    0,      0,
00166                                 0,      0,      0,      0,      0.6,    0,
00167                                 0,      0,      0,      0,      0,      0.1};
00168     for(int i=0; i<36; i++)
00169     {
00170       odom_msg.pose.covariance[i] = odom_covariance[i];
00171     }
00172         
00173     // Publish odometry message
00174     publisherOdom.publish(odom_msg);
00175     
00176     // Also publish tf if necessary
00177     geometry_msgs::TransformStamped odom_trans;
00178     odom_trans.header.stamp = odom_msg.header.stamp;
00179     odom_trans.header.frame_id = odom_msg.header.frame_id;
00180     odom_trans.child_frame_id = odom_msg.child_frame_id;
00181     
00182     odom_trans.transform.translation.x = odom_pos_x;
00183     odom_trans.transform.translation.y = odom_pos_y;
00184     odom_trans.transform.translation.z = 0.0;
00185     odom_trans.transform.rotation = odom_quaternion;
00186     
00187     ros_mutex.lock();
00188     tf_br.sendTransform(odom_trans);
00189     ros_mutex.unlock();
00190 }
00191 
00192 void publishVoltageMsg()
00193 {
00194     std_msgs::Float32 voltage_msg;
00195     voltage_msg.data = battery_voltage;
00196     ros_mutex.lock();
00197     publisherVoltage.publish(voltage_msg);
00198     ros_mutex.unlock();
00199 }
00200 
00201 void publishJoyMsg()
00202 {
00203     sensor_msgs::Joy rc_msg;
00204     
00205     // analog axes
00206     for(int i=0; i<=8; i++)
00207     {
00208         rc_msg.axes.push_back( (remote_analog[i] - 127) / 127.0);
00209     }
00210     
00211     // buttons
00212     for(int i=0; i<=8; i++)
00213     {
00214         for(int bit=0; bit<=8; bit++)
00215         {
00216             if(remote_buttons[i] & (1 << bit))
00217                 rc_msg.buttons.push_back(bool(true));
00218             else
00219                 rc_msg.buttons.push_back(bool(false));
00220         }
00221     }
00222     ros_mutex.lock();
00223     publisherJoy.publish(rc_msg);
00224     ros_mutex.unlock();
00225 }
00226 
00227 void cmdVelCallback(const geometry_msgs::Twist::ConstPtr& msg)
00228 {
00229     ROS_DEBUG("received cmd_vel s=%f y=%f", msg->linear.x, msg->angular.z);
00230     can_send_cmd_vel(msg->linear.x, msg->angular.z);
00231 }
00232 
00233 void can_task()
00234 {
00235     can_running = true;
00236     while(can_running)
00237     {
00238         can_read_frames();
00239     }
00240 }
00241 
00242 int main(int argc, char **argv)
00243 {
00244     ros::init(argc, argv, "innok_heros_can_driver");
00245     ros::NodeHandle n;
00246     ros::Subscriber Sub = n.subscribe("cmd_vel", 10, cmdVelCallback);
00247     
00248     publisherOdom = n.advertise<nav_msgs::Odometry>("odom", 20);
00249     publisherVoltage = n.advertise<std_msgs::Float32>("battery_voltage", 1);
00250     publisherJoy = n.advertise<sensor_msgs::Joy>("remote_joy", 1);
00251     
00252     can_open("can0"); // TODO: parameter for can device 
00253     
00254     boost::thread can_thread(can_task);
00255     
00256     while (ros::ok())
00257     {
00258         ros_mutex.lock();
00259         ros::spinOnce();
00260         ros_mutex.unlock();
00261     }
00262     can_running = false;
00263     can_thread.join();
00264     return 0;
00265 }


innok_heros_driver
Author(s): Alwin Heerklotz
autogenerated on Sat Jun 8 2019 19:16:10