|
| 1 | +// minimal_controller node: |
| 2 | +// wsn example node that both subscribes and publishes--counterpart to minimal_simulator |
| 3 | +// subscribes to "velocity" and publishes "force_cmd" |
| 4 | +// subscribes to "vel_cmd" |
| 5 | +#include <ros/ros.h> |
| 6 | +#include <std_msgs/Float64.h> |
| 7 | +//global variables for callback functions to populate for use in main program |
| 8 | +std_msgs::Float64 g_velocity; |
| 9 | +std_msgs::Float64 g_vel_cmd; |
| 10 | +std_msgs::Float64 g_force; // this one does not need to be global... |
| 11 | + |
| 12 | +void myCallbackVelocity(const std_msgs::Float64& message_holder) { |
| 13 | + // check for data on topic "velocity" |
| 14 | + ROS_INFO("received velocity value is: %f", message_holder.data); |
| 15 | + g_velocity.data = message_holder.data; // post the received data in a global var for access by main prog. |
| 16 | +} |
| 17 | + |
| 18 | +void myCallbackVelCmd(const std_msgs::Float64& message_holder) { |
| 19 | + // check for data on topic "vel_cmd" |
| 20 | + ROS_INFO("received velocity command value is: %f", message_holder.data); |
| 21 | + g_vel_cmd.data = message_holder.data; // post the received data in a global var for access by main prog. |
| 22 | +} |
| 23 | + |
| 24 | +int main(int argc, char **argv) { |
| 25 | + ros::init(argc, argv, "velocity_controller"); //name this node |
| 26 | + // when this compiled code is run, ROS will recognize it as a node called "minimal_controller" |
| 27 | + ros::NodeHandle nh; // node handle |
| 28 | + //create 2 subscribers: one for state sensing (velocity) and one for velocity commands |
| 29 | + ros::Subscriber my_subscriber_object1 = nh.subscribe("velocity", 1, myCallbackVelocity); |
| 30 | + ros::Subscriber my_subscriber_object2 = nh.subscribe("vel_cmd", 1, myCallbackVelCmd); |
| 31 | + //publish a force command computed by this controller; |
| 32 | + ros::Publisher my_publisher_object = nh.advertise<std_msgs::Float64>("force_cmd", 1); |
| 33 | + double Kv = 1.0; // velocity feedback gain |
| 34 | + double dt_controller = 0.1; //specify 10Hz controller sample rate (pretty slow, but illustrative) |
| 35 | + double sample_rate = 1.0 / dt_controller; // compute the corresponding update frequency |
| 36 | + ros::Rate naptime(sample_rate); // use to regulate loop rate |
| 37 | + g_velocity.data = 0.0; //initialize velocity to zero |
| 38 | + g_force.data = 0.0; // initialize force to 0; will get updated by callback |
| 39 | + g_vel_cmd.data = 0.0; // init velocity command to zero |
| 40 | + double vel_err = 0.0; // velocity error |
| 41 | + // enter the main loop: get velocity state and velocity commands |
| 42 | + // compute command force to get system velocity to match velocity command |
| 43 | + // publish this force for use by the complementary simulator |
| 44 | + while (ros::ok()) { |
| 45 | + vel_err = g_vel_cmd.data - g_velocity.data; // compute error btwn desired and actual velocities |
| 46 | + g_force.data = Kv*vel_err; //proportional-only velocity-error feedback defines commanded force |
| 47 | + my_publisher_object.publish(g_force); // publish the control effort computed by this controller |
| 48 | + ROS_INFO("force command = %f", g_force.data); |
| 49 | + ros::spinOnce(); //allow data update from callback; |
| 50 | + naptime.sleep(); // wait for remainder of specified period; |
| 51 | + } |
| 52 | + return 0; // should never get here, unless roscore dies |
| 53 | +} |
0 commit comments