plant_sim.cpp
Go to the documentation of this file.
00001 /***************************************************************************/
00037 // This file simulates a 1st or 2nd-order dynamic system, publishes its state,
00038 // and subscribes to a 'control_effort' topic. The control effort is used
00039 // to stabilize the servo.
00040 
00041 #include <ros/ros.h>
00042 #include <std_msgs/Float64.h>
00043 
00044 namespace plant_sim
00045 {
00046   // Global so it can be passed from the callback fxn to main
00047   static double control_effort = 0.0;
00048   static bool reverse_acting = false;
00049 }
00050 using namespace plant_sim;
00051 
00052 // Callback when something is published on 'control_effort'
00053 void ControlEffortCallback(const std_msgs::Float64& control_effort_input)
00054 {
00055   // the stabilizing control effort
00056   if (reverse_acting)
00057   {
00058     control_effort = -control_effort_input.data;
00059   }
00060   else
00061   {
00062     control_effort = control_effort_input.data;
00063   }
00064 }
00065 
00066 int main(int argc, char **argv)
00067 {
00068   int plant_order = 1;
00069   double temp = 4.7;          // initial condition for first-order plant
00070   double displacement = 3.3;  // initial condition for second-order plant
00071 
00072   ros::init(argc, argv, "plant");
00073   ros::NodeHandle sim_node;
00074 
00075   while (ros::Time(0) == ros::Time::now())
00076   {
00077     ROS_INFO("Plant_sim spinning waiting for time to become non-zero");
00078     sleep(1);
00079   }
00080 
00081   ros::NodeHandle node_priv("~");
00082   node_priv.param<int>("plant_order", plant_order, 1);
00083   node_priv.param<bool>("reverse_acting", reverse_acting, false);
00084 
00085   if (plant_order == 1)
00086   {
00087     ROS_INFO("Starting simulation of a first-order plant.");
00088   }
00089   else if (plant_order == 2)
00090   {
00091     ROS_INFO("Starting simulation of a second-order plant.");
00092   }
00093   else
00094   {
00095     ROS_ERROR("Error: Invalid plant type parameter, must be 1 or 2: %s", argv[1]);
00096     return -1;
00097   }
00098 
00099   // Advertise a plant state msg
00100   std_msgs::Float64 plant_state;
00101   ros::Publisher servo_state_pub = sim_node.advertise<std_msgs::Float64>("state", 1);
00102 
00103   // Subscribe to "control_effort" topic to get a controller_msg.msg
00104   ros::Subscriber sub = sim_node.subscribe("control_effort", 1, ControlEffortCallback );
00105   
00106   int loop_counter = 0;
00107   double delta_t = 0.01;
00108   ros::Rate loop_rate(1/delta_t); // Control rate in Hz
00109 
00110   // Initialize 1st-order (e.g temp controller) process variables
00111   double temp_rate = 0;     // rate of temp change
00112   
00113   // Initialize 2nd-order (e.g. servo-motor with load) process variables
00114   double speed = 0;         // meters/sec
00115   double acceleration = 0;  // meters/sec^2
00116   double mass = 0.1;          // in kg
00117   double friction = 1.0;    // a decelerating force factor
00118   double stiction = 1;      // control_effort must exceed this before stationary servo moves
00119   double Kv = 1;            // motor constant: force (newtons) / volt
00120   double Kbackemf = 0;      // Volts of back-emf per meter/sec of speed
00121   double decel_force;       // decelerating force
00122 
00123   while (ros::ok())
00124   {
00125     ros::spinOnce();
00126 
00127     switch (plant_order)
00128     {
00129     case 1:       // First order plant
00130       temp_rate = (0.1 * temp) + control_effort;
00131       temp = temp + temp_rate * delta_t;
00132 
00133       plant_state.data = temp;
00134       break;
00135 
00136     case 2:       // Second order plant
00137       if (fabs(speed) < 0.001)
00138       {
00139         // if nearly stopped, stop it & require overcoming stiction to restart
00140         speed = 0;
00141         if (fabs(control_effort) < stiction)
00142         {
00143           control_effort = 0;
00144         }
00145       }
00146 
00147       // Update the servo.
00148       // control_effort: the voltage applied to the servo. Output from PID controller. It is
00149       //   opposed by back emf (expressed as speed) to produce a net force. Range: -1 to +1
00150       // displacement: the actual value of the servo output position. Input to PID controller
00151 
00152       decel_force = -(speed * friction);  // can be +ve or -ve. Linear with speed
00153       acceleration = ((Kv * (control_effort - (Kbackemf * speed)) + decel_force) / mass);   // a = F/m
00154       speed = speed + (acceleration * delta_t);
00155       displacement = displacement + speed * delta_t;
00156 
00157       plant_state.data = displacement;
00158       break;
00159     
00160     default:
00161       ROS_ERROR("Invalid plant_order: %d", plant_order);
00162       return(-1);
00163     }
00164 
00165     servo_state_pub.publish(plant_state);
00166     loop_rate.sleep();
00167   }
00168 
00169   return 0;
00170 }
00171 


pid
Author(s): Andy Zelenak , Paul Bouchier
autogenerated on Tue May 2 2017 02:49:51