<?xml version="1.0" encoding="UTF-8"?>        <rss version="2.0"
             xmlns:atom="http://www.w3.org/2005/Atom"
             xmlns:dc="http://purl.org/dc/elements/1.1/"
             xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
             xmlns:admin="http://webns.net/mvcb/"
             xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
             xmlns:content="http://purl.org/rss/1.0/modules/content/">
        <channel>
            <title>
									Two-wheeled robot project using ROS - ROS				            </title>
            <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/</link>
            <description>Discussion board for Robotics, Arduino, Raspberry Pi and other DIY electronics and modules. Join us today!</description>
            <language>en-US</language>
            <lastBuildDate>Fri, 15 May 2026 01:23:05 +0000</lastBuildDate>
            <generator>wpForo</generator>
            <ttl>60</ttl>
							                    <item>
                        <title>RE: Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/paged/2/#post-19331</link>
                        <pubDate>Tue, 13 Jul 2021 20:51:18 +0000</pubDate>
                        <description><![CDATA[Excellent Tutorial!  I have done the wikiROS Tutorials and get a lot of this to work, but they never get down to how the Robot grabs the data and moves in proper direction.  This did a fine ...]]></description>
                        <content:encoded><![CDATA[<p>Excellent Tutorial!  I have done the wikiROS Tutorials and get a lot of this to work, but they never get down to how the Robot grabs the data and moves in proper direction.  This did a fine job of that.</p>
<p> </p>
<p>I very much look forward to lidat, SLAM, obstacle avoidance with lidar implementations.</p>
<p>I see that your posts were form 2 years ago.  Hope I will find more from you on this forum.</p>
<p>Thanks for all the hard work.</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>BigBadJohn</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/paged/2/#post-19331</guid>
                    </item>
				                    <item>
                        <title>RE: Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/paged/2/#post-5007</link>
                        <pubDate>Wed, 23 Oct 2019 01:01:07 +0000</pubDate>
                        <description><![CDATA[Can you tell us what DC motors and controllers you are using on yout two wheel robot. Thanks in advance,Chip]]></description>
                        <content:encoded><![CDATA[<p>Can you tell us what DC motors and controllers you are using on yout two wheel robot.</p><p> </p><p>Thanks in advance,</p><p>Chip</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>Chip</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/paged/2/#post-5007</guid>
                    </item>
				                    <item>
                        <title>RE: Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/paged/2/#post-1189</link>
                        <pubDate>Tue, 09 Jul 2019 07:00:39 +0000</pubDate>
                        <description><![CDATA[Thanks for a great article and very informative write up. I learned a lot from it and hope to be able to implement your ideas in my future projects.hj]]></description>
                        <content:encoded><![CDATA[<p>Thanks for a great article and very informative write up. I learned a lot from it and hope to be able to implement your ideas in my future projects.</p><p>hj</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>hstaam</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/paged/2/#post-1189</guid>
                    </item>
				                    <item>
                        <title>RE: Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1188</link>
                        <pubDate>Tue, 09 Jul 2019 03:14:11 +0000</pubDate>
                        <description><![CDATA[Please let me know if this series of posts has been useful.I enjoyed reading them.  I&#039;ve also book-marked the thread.   When it comes time to program my two-wheeled robots I&#039;ll revisit this ...]]></description>
                        <content:encoded><![CDATA[<blockquote><p>Please let me know if this series of posts has been useful.</p></blockquote><p>I enjoyed reading them.  I've also book-marked the thread.   When it comes time to program my two-wheeled robots I'll revisit this thread.  I probably won't be using ROS, but even without ROS there are many mechanical concepts that would apply in any case.  So I thank you for writing the article.  It was very well written with very nice graphics and code.  Also very nicely organized with topic heading and nicely spaced paragraphs.  I've seen some people try to explain things with such sloppy writing practices that I've had to copy their text, put it into a word processor, and re-organize it myself just to be able to follow what they are doing in a meaningful manner.   So you get the technical Pulitzer prize from me. ? </p><p>Nice Job!</p><p>Material befitting a professional publication to be sure.</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>Robo Pi</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1188</guid>
                    </item>
				                    <item>
                        <title>Part 5- Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1186</link>
                        <pubDate>Tue, 09 Jul 2019 02:32:42 +0000</pubDate>
                        <description><![CDATA[This is the final part of the two-wheeled robot project using ROS.   The first four posts of this topic described the programming model of the robot.  In this post I’ll show the control loop...]]></description>
                        <content:encoded><![CDATA[<p class="p1">This is the final part of the two-wheeled robot project using ROS. <span class="Apple-converted-space">  </span>The first four posts of this topic described the programming model of the robot.<span class="Apple-converted-space">  </span>In this post I’ll show the control loops that drive the robot to its requested destination and orientation.<span class="Apple-converted-space">  </span>The control loops are arranged in cascaded fashion where the outer command loop calls the pose loop which calls the speed control loop.<span class="Apple-converted-space">  </span>I described the speed loop in a previous post, so here I’ll detail the command and pose control loops.</p><p>154</p><p class="p1"><strong>Command Control Loop</strong></p><p class="p1">The command control loop is the outermost loop of our cascaded loop strategy.<span class="Apple-converted-space">  </span>It’ll simply loop waiting for a command to be sent via a callback routine.<span class="Apple-converted-space">  </span>The command will direct the robot to move to a new position and orientation, called a pose.<span class="Apple-converted-space">  </span>For this we use a message type appropriately called “Pose”.<span class="Apple-converted-space">  </span>The <em>Pose</em> message type is explained in the second post of this series.<span class="Apple-converted-space">  </span>Once the command is received it will be sent to the pose control loop that is responsible for moving the robot to the new position and orientation.<span class="Apple-converted-space">  </span>Once the new pose is obtained the program goes back to waiting for a command.<span class="Apple-converted-space">  </span>The process is shown in the flow diagram below.</p><p>155</p><p class="p1">The callback function receives a message to move the robot to a new position and orientation.<span class="Apple-converted-space">  </span>The robot’s current pose is added to the new reference pose.<span class="Apple-converted-space">  </span>This is then used within the pose control loop to apply power to the motors and move the robot.<span class="Apple-converted-space">  </span>A flag is set to tell the main loop that a command has been received.<span class="Apple-converted-space">  </span>The ROSLOGx lines are home grown debug statements that print out to the ROS console.<span class="Apple-converted-space">  </span>If anyone is interested in how these are implemented please let me know. </p><pre> //--------------------------------------------//
// Command callback
//--------------------------------------------//
void commandCb( const geometry_msgs::Pose&amp; cmd) {

  // Print the new pose command message to the ROS console
  ROSLOGString("Received X, Y, Psi");
  ROSLOG3F(cmd.position.x, cmd.position.y, cmd.orientation.y);
  
  // Get the robot's current pose
  float *currentPose = robot-&gt;getLocalPose();

  // Print the robot's current pose to the ROS console
  robot-&gt;driveTrain.printLocalPose();

  // Assign new target pose. Current state + new pose.
  refPose = currentPose + cmd.position.x;
  refPose = currentPose + cmd.position.y;
  refPose = currentPose + cmd.orientation.y / (180/PI); // in radians 

  // Print target pose to the ROS console
  ROSLOGString("Target Pose X, Y, Psi");
  ROSLOG3F(refPose, refPose, refPose);
  
  // Set the commandCalled flag
  commandCalled = true;  
}</pre><p class="p1">The main loop simply waits for a command to be received via the ROS subscribe protocol.<span class="Apple-converted-space">  </span>The <em>nh.spinOnce()</em> statement polls the ROS server for new messages.<span class="Apple-converted-space">  </span>Once the message is received and processed by the callback, the new reference pose is sent to the pose control loop.</p><pre>//-------------------------------------------------//<br />// Main command loop<br />//-------------------------------------------------//<br />void loop() {<br />    <br />  // Loop until command is sent.<br />  if (commandCalled) {<br />    // Position control loop<br />    poseController(refPose);<br /><br />    // Reset commandCalled flag<br />    commandCalled = false;<br />  }  <br /><br />  // Wait for subscribed messages <br />  if (nodeHandleCreated) {nh.spinOnce();}<br />  delay(1000);<br />}</pre><p class="p1"><strong>Pose Control Loop</strong></p><p class="p1">Once we have a command request to move the robot we need to implement a controller to guide it to the new destination and orientation.<span class="Apple-converted-space">  </span>The controller is passed the reference pose that was computed in the command callback function.<span class="Apple-converted-space">  </span>The reference pose becomes the new setpoint for the pose controller.<span class="Apple-converted-space">  </span>The loop starts by calculating the difference between the robot’s current pose and its reference pose.<span class="Apple-converted-space">  </span>The difference is referred to as the error.<span class="Apple-converted-space">  </span>Given the pose error the controller will determine the speed setpoint for the wheels, which is then fed into the speed control loop.<span class="Apple-converted-space">  </span>To complete the loop the new pose state is read from the robot and an updated error calculation is made.<span class="Apple-converted-space">  </span>The loop continues until the pose error is driven to zero.<span class="Apple-converted-space">  </span>There are separate loops for the destination and orientation control.</p><p>156</p><p class="p1">The first thing the <em>poseController</em> does is get the current pose from the robot.<span class="Apple-converted-space">  </span>The current pose is obtained using a vector containing the X, Y positions and the ψ orientation, as shown in the above diagram.<span class="Apple-converted-space">  </span>The current pose is subtracted from the reference pose using a function that subtracts two matrixes.<span class="Apple-converted-space">  </span>The original linear and angular error values are saved since the pose error will constantly change as we process the move loops.<span class="Apple-converted-space">  </span>We first process the linear move followed by the angular move.<span class="Apple-converted-space">  </span>The <em>fabs()</em> function returns the absolute value of a float variable.<span class="Apple-converted-space">  </span>For the angular move the control function takes in an arc radius around which the robot will turn.<span class="Apple-converted-space">  </span>In this case, the arc length is zero requesting that we turn on the spot.<span class="Apple-converted-space">  </span>There’s more detail on this later in the post.</p><pre> //--------------------------------------------//
// Control the position of the robot
//--------------------------------------------//
void poseController(float * refPose) {

  // Get the current x position of the robot
  float *currentPose = robot-&gt;driveTrain.getLocalPose();

  // Subtract the target pose from the current pose to get the error
  Matrix.Subtract(refPose, currentPose, 3, 1, poseError);

  ROSLOGFLabel("Start error X", poseError);
  ROSLOGFLabel("Start error Psi", poseError);

  // Save the original pose errors
  float linear_error = poseError;
  float angular_error = poseError;
   
  // -------- Process linear error ------------------
  if (fabs(linear_error) &gt; 0.0) { 
    moveLinear();
  } 

  // -------- Process angular error -----------------
  if (fabs(angular_error) &gt; 0.0) {
    // Pass in the arc length
    moveAngular(0.0); // Turn on the spot
  }   
}</pre><p class="p1"><strong>Linear Move</strong></p><p class="p1">The code to move the robot in a straight line towards the reference destination is shown below.<span class="Apple-converted-space">  </span>We first save the direction sign, positive for forward direction and negative for backwards.<span class="Apple-converted-space">  </span>This will be used within the control loop to determine if we’ve overshot our target position.<span class="Apple-converted-space">  </span>We set our wheel to the maximum speed and initialize a loop counter.<span class="Apple-converted-space">  </span>The loop counter is used to implement a timeout.<span class="Apple-converted-space">  </span>This is especially useful during testing so as you’re not running after the robot if the code is incorrect.<span class="Apple-converted-space">  </span>Initializing the wheel to maximum speed does result in a jolt at the beginning of the move.<span class="Apple-converted-space">  </span>This is mitigated somewhat in the speed control loop where it takes several time periods to reach the maximum PWM value.<span class="Apple-converted-space">  </span>However, I do intend to implement a smoother startup transition at a later point. </p><p class="p1">We’re now ready to enter the control loop that continues until the X position error is driven to zero.<span class="Apple-converted-space">  </span>The loop is processed every 50 milliseconds and is timed out after 5 seconds for testing purposes.<span class="Apple-converted-space">  </span>If the sign of the pose error changes then we have gone passed our target position and we immediately break the loop and stop the motors.<span class="Apple-converted-space">  </span>We want to slow down as we reach the target position so I’ve setup a couple of constants that start to reduce the motor speeds as we get to within 15% of the reference position.<span class="Apple-converted-space">  </span>The <em>Ki </em>value ensures that we maintain a minimum speed at all times.<span class="Apple-converted-space">  </span>These values can be tuned experimentally.<span class="Apple-converted-space">  </span>The calculation will result in the maximum speed exceeding 1.0 during most of the run so we account for this condition in the code.</p><p class="p1">The new left and right wheel speed values are sent to the motors, and we go on to read the new pose value from the robot.<span class="Apple-converted-space">  </span>The new error is calculated and we return to the top of the control loop.<span class="Apple-converted-space">  </span>The loop is exited when the error is driven to zero and the command to stop the motors is sent.</p><pre> // PI control for pose loop. Adjust gain constants as necessary
const float Kp = 1.5; // Gets within 15% of target 
const float Ki = 0.3; // Maintains a minimum speed of 0.3
//----------------------------------------------//
// Move in a straight line forward or backward
//----------------------------------------------//
void moveLinear() {

  // Save the direction of motion
  int dir = sgn(int(poseError * 1000)); 
  
  // Set min and max speed.
  float maxSpeed = 1.0;
  float wheelSpeed = maxSpeed;
  int loopCounter = 0; // Loop counter for timeout
  
  while (fabs(poseError) &gt; 0.0) {

    // Process the loop every 50 milliseconds
    current_time = nh.now().toSec();
    while(nh.now().toSec() &lt; current_time + poseLoopPeriod) {
        //wait 50ms
    }

    // Timeout after 5 seconds
    if (loopCounter &gt; timeOut) { ROSLOGString("Timed out!"); break; } 

    // End loop if the direction sign has changed (went passed the target)
    if ( sgn( int(poseError * 1000) ) != dir ) { break; }
    
    // Actuate the wheels 
    
    // Slows down when we get near the target position
    // Sets wheel speed proportionally to the position error
    wheelSpeed = (poseError * Kp) + (Ki * dir); // Kp = 2.0, Ki = 0.3

    // Keep max speed to 1.0
    if (fabs(wheelSpeed) &gt; maxSpeed) { 
      wheelSpeed = (maxSpeed * dir); // Max 1.0
    } 
    ROSLOGFLabel("wheelSpeed", wheelSpeed);
    
    robot-&gt;setWheelSpeeds(wheelSpeed, wheelSpeed); // left and right wheel

    // Get the current x position of the robot
    float *currentPose = robot-&gt;getLocalPose();

    // Calculate the error
    Matrix.Subtract(refPose, currentPose, 3, 1, poseError);

    publishToROS(currentPose);  // Publish robot state to ROS
     
    loopCounter++;
    
  } // End while loop

  // Stop the wheels
  robot-&gt;setWheelSpeeds(0.0, 0.0);  // Stop
  ROSLOGString("--- Done linear movement ---");
}</pre><p class="p1">Note that since the robot is referenced in the local frame the move along the linear X position always sends the robot straight ahead regardless of where it’s initially pointing.<span class="Apple-converted-space">  </span>There’s no global X position within a space that we’re trying to get to.<span class="Apple-converted-space">  </span>I’ve tried to illustrate this in the following diagram.<span class="Apple-converted-space">  </span>In the next series of posts I’m going to place the robot within a global frame in preparation for mapping and localization.</p><p>100</p><p class="p1"><strong>Angular Move</strong></p><p class="p3"><span class="s1">Before looking at the control loop that implements a change in orientation we need to define a point around which the robot’s wheels can rotate.<span class="Apple-converted-space">  </span>This point is called the <em>instantaneous center of rotation</em> (ICR) and </span><span class="s2">defines a point around which both wheels follow a circular motion.<span class="Apple-converted-space">  </span>To obtain an angular movement the inside wheel would need to spin slower than the outside wheel, which can be accomplished successfully with a differential drive robot.<span class="Apple-converted-space">  </span>The following diagram shows the math involved.</span></p><p>157</p><p class="p1">The following function is a member of the <em>DriveTrain</em> class.<span class="Apple-converted-space">  </span>It takes in an arc radius and returns the ratio between the inside and outside wheels.<span class="Apple-converted-space">  </span>If you follow the calculation through you’ll find that an arc radius of zero will return a ratio of 1.0, resulting in the robot turning on the spot.</p><pre> // ----------------------------------------------------------------
// Calculate the ratio between the two wheels while driving in
// an arc. arcRadius is the Instantaneous Center of Rotation (ICR)
// ----------------------------------------------------------------
float DriveTrain::calculateArcWheelRatios(float arcRadius) {
  
  // Get the distance that each wheel has to travel
  float insideWheel = 2*PI * ( arcRadius - (wheelSeparation/2) );
  float outsideWheel = 2*PI * ( arcRadius + (wheelSeparation/2) );

  // Return the ratio between the two wheels 
  return (insideWheel / outsideWheel);
}</pre><p class="p1">The <em>moveAngular()</em> function follows a similar pattern to the <em>moveLinear()</em> function.<span class="Apple-converted-space">  </span>Since our wheels need to move at different speeds the ratio between the left and right wheel is obtained from the <em>calculateArcWheelRatios()</em> function, explained above.<span class="Apple-converted-space">  </span>The resulting ratio will be between 1.0 and 0.0 so it must therefore applied to the slower spinning inside wheel.<span class="Apple-converted-space">  </span>For turns, I’ve set the maximum speed to 50%.<span class="Apple-converted-space">  </span>We then enter the main orientation control loop.</p><p class="p1">The primary difference between the orientation and linear control loops is that the wheels are moving at different speeds.<span class="Apple-converted-space">  </span>We first calculate the speed for the outside wheel and apply our ratio to get the inside wheel speed.<span class="Apple-converted-space">  </span>Note that the ratio will be 1.0 for a turn on the spot and that one wheel will be moving forward while the other is going backwards.<span class="Apple-converted-space">  </span>This will be the case whenever the arc radius is less than half the length of the wheel base.<span class="Apple-converted-space">  </span>At some point we have to decide which wheel is the inside wheel.<span class="Apple-converted-space">  </span>This depends of course on whether we’re turning left or right.<span class="Apple-converted-space">  </span>The determination is made and sent to the robot to actuate its motors.<span class="Apple-converted-space">  </span>The remainder of the process is the same as for the linear move.</p><pre>//----------------------------------------------//
// Move in an arc clockwise or anti-clockwise
//----------------------------------------------//
void moveAngular(float arcRadius) {

  // Calculate the relative wheel speeds based on the 
  // radius of the turn.
  float ratio = robot-&gt;calculateArcWheelRatios(arcRadius);
  
  // Save the direction of motion
  int dir = sgn(int(poseError * 1000)); 

  // Use half of max speed for turn.
  float maxSpeed = 0.5;

  // Set initial wheel speeds
  float outsideWheelSpeed = maxSpeed;
  float insideWheelSpeed = maxSpeed * ratio;
  
  int loopCounter = 0; // Loop counter for timeout
  
  while (fabs(poseError) &gt; 0.0) {

    // Process the loop every 50 milliseconds
    current_time = nh.now().toSec();
    while(nh.now().toSec() &lt; current_time + poseLoopPeriod) {
        //wait 50ms
    }    

    // Timeout after 10 seconds
    if (loopCounter &gt; (timeOut*2)) { ROSLOGString("Timed out!"); break; } 

    // End while loop if the direction sign has changed (went passed the target)
    if (sgn( int(poseError * 1000) ) != dir) { break; }

    // Slows down when we get near the target orientation
    // Sets the outside wheel speed proportionally to the orientation error
    float outsideWheelSpeed = (poseError * Kp) + (Ki * dir); // Kp = 3.0, Ki = 0.3

    // Keep max speed to 1.0
    if (fabs(outsideWheelSpeed) &gt; maxSpeed) { 
      outsideWheelSpeed = maxSpeed; // Max 1.0
    } 

    // Calculate the inside wheel speed. Ratio will be -1 for turn on the spot
    insideWheelSpeed = outsideWheelSpeed * ratio;
    ROSLOG2FLabel("Wheel speeds (left,right)", insideWheelSpeed, outsideWheelSpeed);
    
    // Actuate the wheels
    if (poseError &gt; 0.0) { // Moving anti-clockwise. Inside wheel is left
      robot-&gt;setWheelSpeeds(insideWheelSpeed, outsideWheelSpeed); // (left wheel, right wheel)
    } 
    else { // Moving clockwise. Outside wheel is left 
      robot-&gt;setWheelSpeeds(outsideWheelSpeed, insideWheelSpeed); // (left wheel, right wheel) 
    }

    // Get the current x position of the robot
    float *currentPose = robot-&gt;getLocalPose();

    // Calculate the error
    Matrix.Subtract(refPose, currentPose, 3, 1, poseError); 

    publishToROS(currentPose);  // Publish robot state to ROS
    
    loopCounter++;
    
  } // End while loop

  // Stop the wheels
  robot-&gt;setWheelSpeeds(0.0, 0.0);  // Stop
  ROSLOGString("--- Done angular movement ---");
} </pre><p class="p1">This completes phase one of the project.<span class="Apple-converted-space">  </span>Please let me know if this series of posts has been useful.<span class="Apple-converted-space">  </span>If so, I’ll continue to write updates on the project as it progresses.<span class="Apple-converted-space">  </span>In the next phase I’ll be working at controlling the robot within a global reference frame, such as a living room (external kinematics).<span class="Apple-converted-space">  </span>I’d also like to try and use an MPU for dead reckoning to confirm the odometry results coming from the encoders.</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>mjwhite</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1186</guid>
                    </item>
				                    <item>
                        <title>RE: Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1185</link>
                        <pubDate>Tue, 09 Jul 2019 02:02:26 +0000</pubDate>
                        <description><![CDATA[Thanks for addressing the first question twobits.  I didn&#039;t come across that error so I would have been struggling on it.2) If the ROS-pi is the publisher, do you have an esp8266 (or somethi...]]></description>
                        <content:encoded><![CDATA[<p>Thanks for addressing the first question twobits.  I didn't come across that error so I would have been struggling on it.</p><blockquote><p>2) If the ROS-pi is the publisher, do you have an esp8266 (or something like it) on an arduino as the subscriber ? (you said to connect to the network address of the ros)</p><p>And then the arduino would send the signals to the motor controller ? (md10c or l298n or something)</p></blockquote><p>The message is published from the command line on the Pi.  It takes the form of:</p><pre class="p1"><span class="s1">rostopic pub -1 /pose_cmd geometry_msgs/Pose '{position:<span class="Apple-converted-space">  </span>{x: 1.0, y: 0.0, z: 0.0}, orientation: {x: 0.0,y: 0.0,z: 0.0, w: 0.0}}'</span></pre><p>where 1.o requests a one meter change in the X position of the robot.  I have an ESP32 running the robot code that is subscribing to the Pose message sent from the Pi.  The Raspberry Pi runs the <em>roscore</em> server process which acts as the publish/subscribe exchange.  This is the network address of ROS that I refer to.</p><p>The motors are actuated through an L298N in my case.</p><blockquote><p>3) You covered encoders in the motors. The motors that @Bill picked up for DB1 have built in hall type encoders (I ordered the same ones. In fact, I ordered most of the same parts so I could use whatever code he finally publishes) If the arduino is only a subscriber, what happens to the data from the encoder ? It looks like you're saying that it goes back to the pi, but, it also looks like you're saying that it goes to the microcontroller</p></blockquote><p>The data from the encoders is used to control the motor speeds.  This is done in the <em>DCMotor::setPower()</em> function.  It's also used to compute the new position of the robot that is subsequently published to the ROS server.  At this point I don't do anything with the published data other than to view it in a charting tool for debugging. The published output can also be captured in a file that ROS calls a <em>bag</em>.  It can then be played back in RVIS which is a ROS visualization tool.</p><p>I hope this answers your questions.  Please let me know if there's anything else.</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>mjwhite</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1185</guid>
                    </item>
				                    <item>
                        <title>RE: Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1184</link>
                        <pubDate>Tue, 09 Jul 2019 01:34:40 +0000</pubDate>
                        <description><![CDATA[Getting used to the ROS community takes a little time if you are used to working with Linux or other open source project with a GPL license. Those projects, including the documentation, tend...]]></description>
                        <content:encoded><![CDATA[<p>Getting used to the ROS community takes a little time if you are used to working with Linux or other open source project with a GPL license. Those projects, including the documentation, tend to be very collaborative.</p><p>ROS uses a different open source license call BSD. It feels more like people just throw their code out into the wide and forget about once they have written their paper or completed a project.</p><p>I can see why universities and the manufactures who fund research like BSD, but is has taken me a while to get used to it.</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>twobits</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1184</guid>
                    </item>
				                    <item>
                        <title>RE: Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1177</link>
                        <pubDate>Mon, 08 Jul 2019 22:07:45 +0000</pubDate>
                        <description><![CDATA[Please let us know how it goes. If you have any trouble I&#039;ll write an installing ROS on Raspian script and upload it to git hub.]]></description>
                        <content:encoded><![CDATA[<p>Please let us know how it goes. If you have any trouble I'll write an installing ROS on Raspian script and upload it to git hub.</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>twobits</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1177</guid>
                    </item>
				                    <item>
                        <title>RE: Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1176</link>
                        <pubDate>Mon, 08 Jul 2019 22:00:26 +0000</pubDate>
                        <description><![CDATA[Updating the documentation, what a novel ideaSomebody should suggest that to themI will give the wiki addy you posted a shot. Thank you]]></description>
                        <content:encoded><![CDATA[<p>Updating the documentation, what a novel idea</p><p>Somebody should suggest that to them</p><p>I will give the wiki addy you posted a shot. Thank you</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>Spyder</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1176</guid>
                    </item>
				                    <item>
                        <title>RE: Two-wheeled robot project using ROS</title>
                        <link>https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1174</link>
                        <pubDate>Mon, 08 Jul 2019 20:33:06 +0000</pubDate>
                        <description><![CDATA[I can help you with the first question&#039;Couldn&#039;t find the repository&#039; must qualify as one of the top 10 least helpful error messages of all time. In this case it usually means that there is a...]]></description>
                        <content:encoded><![CDATA[<p>I can help you with the first question</p><p>'Couldn't find the repository' must qualify as one of the top 10 least helpful error messages of all time. In this case it usually means that there is a problem with the repository key. A couple of months ago ROS had an issue with their key so they issued a new key. Very few tutorial have been updated to reflect the new key.</p><p>I usually follow the instruction  found at http://wiki.ros.org/ROS/Installation click on the version of ROS you want to use. Then select Debian to get the key for the Debian/raspian release.</p>]]></content:encoded>
						                            <category domain="https://forum.dronebotworkshop.com/ros/">ROS</category>                        <dc:creator>twobits</dc:creator>
                        <guid isPermaLink="true">https://forum.dronebotworkshop.com/ros/two-wheeled-robot-project-using-ros/#post-1174</guid>
                    </item>
							        </channel>
        </rss>
		