Tutorial: NXT Segway with RobotC

Last update: 10 November 2012

This tutorial will show you how to use and modify RobotC program code to create a working LEGO NXT Segway that you can customize as you like. Although you can use any type of LEGO NXT Segway with this code, I am assuming you will use the ‘Anyway’ platform. I recommend that you start here and modify your Segway only once you finish this tutorial — when you have a working Anyway Segway.

RobotC or NXT-G?

If you are not comfortable with RobotC or if you’re not sure what you’re doing, consider programming your Segway using the original LEGO NXT-G Software. Click here for a tutorial for NXT-G. Otherwise, proceed to programming the Segway with RobotC.

0. Quick start (if you don’t like to read)

Just download the programs and run. I’ve added comments to the programs that can replace this tutorial. You can always return here, if you like.

1. Requirements and preparation:

2. Getting started: Balancing for the first time:

Before moving on to more advanced programs, we’ll first configure and run a simple program that will make the Segway balance and just stay in the same place.

  • In RobotC, open “Segway-NoAction.c”. (This is in the folder you unzipped the downloaded archive to).
  • Press F7 (Compile). Proceed to the next step if there are no errors. If this gives errors, this may indicate that you did not correctly follow the preparation steps.
    • If you see (among other errors): **Severe*:Couldn’t open ‘#include’ file ‘drivers/DIMU-driver.h or MICC-driver.h, or similar, this means that the driver suite is not correctly installed. Consult the driver installation video.
    • If you see (among other errors): **Severe*:Couldn’t open ‘#include’ file ‘segway-driver-lv.h, then the files in the zipped archive were not successfully unzipped to a single folder. Unzip again and retry.
  • Now consider the following code fragment that you see in your example program:
Configuring your Segway
  • You use one of the first four lines to tell the program which gyro sensor you have. Presently, this example is configured to work with the dIMU sensor from Dexter Industries. If you use the HiTechnic, Mindsensors or Microinifnity sensor, simply comment out the one from Dexter Industries and uncomment your sensor.
  • tSensors Gyro = S2; specifies which sensor port you connect your gyro sensor to. Plug your sensor cable into this port, or replace S2 by S1, S3 or S4.
  • Use your_wheel_diameter to let your code account for the robot’s wheel diameter. The default is 42 mm for standard NXT 2.0 tyres. Use 56 mm for standard NXT 1.0 wheels. The large RCX tyres are 84 mm in diameter.
  • When you’re done, press F5 (Compile and Download Program).
  • Start the program on the NXT brick (Make sure your batteries are charged!).
    • If you configured the program to use the HiTechnic Gyro, follow the on-screen instructions
    • If you use the IMU from Dexter Industries or Mindsensors or the Microinfinity Cruizcore , just hold your Segway upright and start the program. Then immediately let go.
  • When you’re done clapping your hands in excitement, have a look at the main task of your code. This basic set of lines will form the core structure of your future programs based on this code.
The main task in the most basic Segway program
  • For more explanation on how to control your Segway, proceed to the next section.

3. Driving, turning, and avoiding walls:

Now that you’ve successfully got your robot up and running, customize the code to make the robot move around. The Segway driver has been programmed so that you won’t have to worry about balancing. You can just run normal programs as long as you keep the following things in mind.

  • To get going quickly, open and run “Segway-Explanation(Wall-Avoidance).c”. The comments in this file will tell you what you need to know for further customization.
  • You can use regular loop, wait and other expressions but controlling movement should not be done with regular motor controls. Do not draw too much CPU power as it may conflict with the balancing task! That is, do not use empty while loops.
  • There are three variables that control the Segway’s movement. Note that in using these, you are not directly controlling the motors, you’re just sending inputs to the actual control code.
    • steering: This integer variable controls the tightness of the robot’s turn or its turn in place if not driving. There’s no strict limit here, but take steering = -20; as a sharp left turn, -10 as a soft left turn, 0 as no turning, and 20 as a sharp right turn.
    • speed: This integer variable makes the Segway drive. Its value is of the same order of magnitude of regular motor speed. For example, speed = 50; will make the Segway go forward, 0 is stand still, and -30 is an example of driving backwards.
    • acceleration: This integer controls the maximum acceleration your robot will do. If your speed is, say, 50 (set previously) and then you specify -10 as your new speed, this doesn’t happen instantly. When acceleration is set to, say, 30, it would take 2 seconds to accomplish the described new speed (50 – 30*1 – 30*1 = -10). If you’re unsure about this one, just don’t modify it and you’ll be fine.
  • Your robot will keep on doing what you specified it to do until you specify a different action (different values of speed and steering)!
Segway Wall Avoidance Example. Notice how 'speed' and 'steering' can be used to control the robot's movement.

The following video shows the Segway wall-avoidance program in action.

Optional: Using the built-in Motor Encoders:

You are not allowed to control motors B and C in your program, but it’s still perfectly fine to read the motor encoders so you can do your own position control.

  • Run the “Segway-Encoders.c” example program. The robot will drive back and forth repeatedly between its starting position and another position.
  • Because the NXT motors are oriented ‘in reverse’, you should take into account the target position of the encoder. When you have speed set positively to go forwards, the encoder value will decrease. The example program illustrates this.
  • If you use while loops for polling your sensor, be sure to add Wait statements (e.g. 100 mSec, although you *can* go lower) in the loop to save CPU power. This way, you won’t affect the balancing control task too much.
Using the built-in motor encoders

Optional: Tuning the PID Controller for improved balance

If you want to further customize the code without going into too much detail, you can do so by modifying a few variables that strongly influence balancing behavior. You can modify their values to change this behavior. This is useful if you want your robot to respond faster to disturbances, or if you are building a robot different than the Anyway. See these values below. You can change these inside the driver file, or in your main control code (they are globally accessible).

The Segway uses a PID controller to keep balance. Four physical signals are repeatedly measured and controlled to stay closely to zero at all times. These signals are:

  • Robot angle relative to perfect balance (angle theta, or short: th)
  • Robot angular velocity: change of angle in time (dtheta/dt, or short: dth_dt)
  • Motor encoder position: position of the wheels (position y)
  • Motor encoder speed: change of position in time (dy/dt, or: dy_dt)

Ideally, when they’re each zero, the robot stands perfectly still and upright (take some time to think about this!). In reality, they will always vary in time. Variance relative to the desired zero position could be considered as an error. The error is the added total of these four error signals, each multiplied by a relative importance factor (a gain). After all, staying upright is more important than staying in one place. You change the gain (short: gn) values to increase or decrease the relative importance weighing factors. They are the first four values in the illustration below.

Having established the total added error, we want to keep the total error close to zero. To do this, we use a PID controller. Roughly speaking, this means the power applied to the driving motors is the sum of the total error (Proportional), the accumulated error in time (Integral), and the change of the error in time (Derivative). Again, each of these are multiplied by a relative weighing factor: kp, ki and kd respectively. These are the last three values in the illustration.

Although the exact theory goes much further than this description, I encourage you to experiment with these values to see how you can change the balancing behavior. Don’t worry about losing the original values — you can always download a fresh copy of the driver file on this page.

These values can be varied to improve balancing control.

Feedback: Help improve this tutorial

Did you find this tutorial useful? Let me know in the comments. If you run into problems, let me know as well so I can improve the tutorial where necessary.


The very first version of this code was inspired by ‘Coordinated LEGO Segways’ by Steven J. Witzand. You can find a very informative thesis and Matlab/Java code here.

About the author

104 Responses
  1. Hey great build!

    I just got my dIMU, and, when trying to compile the “Segway-No-Action” program, I get this error:

    **Error**:Procedure call Parameters don’t match declaration for ‘DIMUconfigGyro(tSensors link, unsigned ubyte range)’

    Any idea what the problem might be?

    PS: I’m on Windows 7, RobotC version 3.5 (F/W: 9.07)

    1. To fix this, install the latest RobotC third party driver suite. See updated link in the article.

      (@ Leon,

      I’ve updated and removed some of our discussion to make it easy to read for people with this problem. Since we’ve solved your problem, I hope that’s OK with you 🙂 )

  2. Sorry, another question: I just tried the first program (using all the defaults; with NXT 2.0 wheels), and all it does is drive the wheels in what seems like the wrong direction really fast for about a second and then aborts the program. Is that supposed to happen?

    1. Check sensor cables and motor cables. You should hold the Segway upright when you start the program. The program is automatically aborted when the robot detects it has crashed.

      1. Sakthi

        Even, I have the same problem. I have checked everything. Still couldn’t make the robot balance. Your help is much appreciated. Thanks.

  3. Bob

    Hi Laurens

    This is a brilliant project that I really enjoyed building. I now want to delve further and wondered if you could please show me how you worked out the 4 state variable gains and the 3 PID values. You can assume that I can handle degree level maths.

    Many thanks


      1. dexter

        I am trying to build self balancing robot using lego EV3 with RobotC platform. the sensor used is gyroscope and built in motor encoders. Can anyone provide me the source code for such a robot using ev3 and robotc?

  4. Josef

    Hi Laurens,

    great tutorial!
    With RobotC I integrated a joystick control, now I can drive around with the Anyway (with Dexter IMU) 🙂
    I think I can grasp the concept of PID control, but there are many things I do not quite understand:
    u = -1.68*DIMUreadGyroAxis(Gyro, DIMU_GYRO_Z_AXIS);
    When you read the gyro, what is the meaning of “-1.68”?

    When I turn off the motors and just monitor the value of the angle theta, I can see that the value is drifting (as is the case with most gyros).
    If I tilt the Segway a noticeable angle and back, the readings seem to be even more off.

    You do not seem to use a Kalmann or complementary filter on your data.
    What have I overlooked, and why is the balancing working nevertheless?



    1. Hey Josef,

      Thanks! Glad to hear the code is being studied 🙂

      The -1.68 does not have a physical meaning. I started off with the HiTechnic Gyro, and created all PID constants to fit that. If I multiply dIMU reading by -1.68, it scales roughly the same as the HiTechnic one. This way, they can use the same PID constants regardless of the sensor in use.

      The dIMU produces slightly lower values than the HT (1.68 times as low). And due to orientation on the Anyway, I multiply it by -1.

      Frankly, I’ve also never really understood that drift in the case of this program. If you display theta on the screen, you’ll notice it is not 0 while it does stand straight up. In the PID, a balance arises between position offset and apparent angle offset. The total error does equal 0 or moves around it.

      Next year I’ll be studying stuff like those filters as part of my study. I hope that by then I have a better sense of how it all really works.


  5. Brian

    I am finding my robot jerking around a little bit and am trying to adjust the values of the PID control. However, I am having some difficulty reading your header file.

    Could you please provide which variable is the Proportional, Derivative and Integral as well as others I may need for debugging?

    I originally planned to make a bluetooth remote control segway (it does work) but the segway does not balance as effectively as I want it to especially when I want it to move quickly.

    1. Hi Brian,

      The values you’ll want to change are the 7 values listed in the last paragraphs of this tutorial.

      The first 4 are listed in the text, and kp, ki, kd are for proportional, integral and derivative action, respectively.

      You can change each of these in your main program so you won’t have to change the header.

      If you don’t change them in your main program, the default values from the header are used. Example:

      task main()
      //Start balancing and wait for configuration to finish

      kp = 5;
      ki = 4;

      //And because we don’t change kd, it keeps its default value.


  6. Dr. John S. Colonias

    Laurens, Hi

    I just to congratulate you for the excellent work you have done in
    constructing and publishing your Segway project. Your instructions
    were perfect. My Segway worked the first time, both the static case
    as well as moving around. My students were very impressed with your

    Keep it up, and thanks.


  7. Rory

    To start of I am very glad you wrote most of my code for me… Being one of my teams programmers in the FTC tournament, I was trying to learn how to use a Gyro sensor and drivers better. I got the segway to stand up tried to create my own teleop program for it. I got some issues with the robot not being able to move backward and that it stutters when turning left. Here is my code…

    #define HiTechnic_Gyro

    const tSensors Gyro = S2;
    const float your_wheel_diameter = 42;

    #include “segway-driver-lv.h”
    #include “JoystickDriver.c”

    task main()

    if(joy1Btn (4) == 1)
    speed = 50;
    if(joy1Btn(2) == 1)
    speed = -50; //Here I am having issues
    if(joy1Btn(1) == 1)
    steering = -17; //Here I am having issues

    if(joy1Btn(3) == 1)
    steering = 17;
    steering = 0;
    speed = 0;

    1. Hi Roy,

      Glad to hear the standard program worked right away. I think you’ll need to add Wait1MSec(20); at the end of the loop.

      Presently you’re polling the joystick more often than the Segway code can respond to, so you should not loose performance in doing this.

      Also, you might want to use more Else statements. For instance, you go either backward or forwards, not both at the same time. So add the ‘else’ as follows:

      if(joy1Btn (4) == 1)
      speed = 50;
      else if(joy1Btn(2) == 1)
      speed = -50; //Here I am having issues

      The stuttering could be explained by two conflicting commands that you give, such as telling it to go right or left at the same time.

      Let me know if this helps.



  8. didier

    LEGO MINDSTORMS NXT Segway program driver


    after the NXT G ( WONDERFULL…), I try the ROBOT C ;

    My gyro HiTechnic on NXT with robot C and drivers needed on the blog works well;

    but when I want to compile download in NXT the

    LEGO MINDSTORMS NXT Segway program driver

    the screen says

    ” no program to compile ”

    please , what could happen ?



    1. didier


      now it compile and download ;( after it take his lunch … ???)

      I put the wheel raduis ( 42/1000 );

      it says ” file error ” on NXT screen when start then stop;

      so much things to learn ;


  9. aswin.bouwmeester@gmail.com

    Hi Laurens,

    Great job.
    Did you realize that you have nested PID controllers. The first two are angular speed (P) with angle (I, as angle is the integral of angular speed) and location (P) with speed (D, as speed is the derivative of location). Then you feed thie sum of these two to a third PID controller.
    Anyway, it works like a charm.

    1. Hi Aswin,


      I wrote the original version of this code in 2009/2010 when I was in high school, with zero to no knowledge about PID controllers. The addition of these four terms to find the combined error was inspired by this paper: http://code.google.com/p/gelway/downloads/list

      Now that I know something about control theory a few years later, I’d have to sit back and read that paper again, this time actually understanding it. But since the code works quite well, I haven’t taken the time to do that yet.

      I may have misinterpreted what’s in the paper back then, or the paper doesn’t have it entirely correct. Either way, the combined error principle was taken from the “BalanceController.java” Source Code, in the appendix of the paper.


  10. Sander

    Hoi Laurens, ik heb sinds kort een dIMU sensor en heb met succes jouw segway nagebouwd en de code met robotc erin gezet. Nu heb ik ook een Hitech irreceiver die ik wil gebruiken om de segway te besturen, helaas kom ik geen steek verder na uitgebreid te hebben rond gezocht naar een voorbeeld code die ik zou kunnen gebruiken. Juist van voorbeeld codes leer ik een hoop dus is mijn vraag of jij mij wat verder zou willen helpen.

  11. maximurx


    we have build the segway according the tutorial (NXT 1.0) with the dexter industries sensor. Now first problem was (but solved): we use the RobotC 3.51, this lead to incompatible drivers which we also downloaded fresh.
    There was no “drivers/DIMU-driver.h” or “MICC-driver.h” and not because of wrong installation, no, as one of the recent changes was to RENAME the files …
    So we changed the source-code accordingly to
    #include “drivers/dexterind-imu.h”
    #include “drivers/microinfinity-cruizcore.h”
    and yeah – it works … a bit

    When we run the Segway-Wall-avoidance it works patially. The robot balances right and turns if something is regisered, but does no forward or backwad move. The speed parameter has no meaning. Have tried everything … any idea ?

    Thanks a lot in advance.

      1. maximurx

        My son would love, to have it working THIS weekend … is there a chance ?

        Also: I am programming C since 1989. I haven’t looked too much into RobotC but I expect to understand it 😉 Maybe I can help out ?

  12. jiří b

    I have Inertial Motion Unit.
    But RobotoC writes error: #include “drivers/DIMU-driver.h”

    and:File “Segway-NoAction.c” compiled on Oct 04 2012 22:00:53
    **Severe*:Couldn’t open ‘#include’ file ‘drivers/DIMU-driver.h’

    but who is me mistake?? thanks

    1. maximurx


      I had the same problem and solved it but … you will see yourself:

      We use the RobotC 3.51, this lead to incompatible drivers which we also downloaded fresh.
      There was no “drivers/DIMU-driver.h” or “MICC-driver.h” and not because of wrong installation, no, as one of the recent changes was to RENAME the files …

      So we changed the source-code accordingly to
      #include “drivers/dexterind-imu.h”
      #include “drivers/microinfinity-cruizcore.h”
      and yeah – it works … a bit

      Hope this helps …

      1. Thanks maximurx for helping out jiří b. It is indeed the solution.

        I’m working on an updated version to reflect the changes in RobotC 3.51. Also “It works a bit” – it should work just as in the videos 🙂



  13. Jonathan

    Hi Laurens.

    I hope you’re doing well, i thank you for the code, but if it’s not too much, can you make a tutorial of how to do the programing of the balancing part…

    thank you

    1. Hi Jonathan,

      The program requires the understanding of PID control.

      There are numerous control theory books out there that cover PID, but you will also find many short tutorials describing just the essentials.



        1. What’s “those your code”? You can already download the code from this page…

          If you want to learn more about programming, you shouldn’t start with something this complicated – you should start with the basics.

          1. Sam

            Hi laurens,

            Indeed we programmed the sonar, the gyro sensor with the software “robotc”, but we need help about the infrared receiver. Do you have any track and any track about enslavement? Or if you have example of program?

            Thanks you very much and thank you for answer.

  14. maximurx

    Hi Laurens,
    I’ve made a few test with only motor movements with new RobotC 3.51. It looks that there is a problem letting both motors in a two motor configuration turn backwards …
    Just didn’t understood it …

  15. samir

    hi laurens,

    i work on NXT segway, and i would like to know how we program the liaison between the command and the Ifrared receiver ?

    thank you.

  16. sam

    Hi laurens,

    Indeed we programmed the sonar, the gyro sensor with the software “robotc”, but we need help about the infrared receiver. Do you have any track and any track about enslavement? Or if you have example of program?

    Thanks you very much and thank you for answer.

    1. I think you will need to read the sensor value inside the control loop, to avoid any problems of trying to read two sensors at the same time.

      So in the main program add one line as shown:
      /*SELECT SENSOR PORT (S1, S2, S3 or S4), and WHEEL DIAMETER (milimeters).*/
      const tSensors Gyro = S2;
      const float your_wheel_diameter = 42;

      int ir_receiver_value;//This is the line that you add

      And in the segway-driver-lv.h:

      ir_receiver_value = //Here, you add the command to read the sensor, just as in the examples.

      while(time1[T4] < dt*1000){ wait1Msec(1);}//This part is already in the code! ClearTimer(T4); Finally, in the main program, you can now use the ir_receiver_value variable, which contains the latest value of the sensor. For example: speed = ir_receiver_value*2; I do not have this sensor, so I do not exactly know what values it gives, but that's something that the sensor examples will teach you.

      1. Sam


        Know we would like to know how the robot can move and remain in balance? We testing it and we need your precious help.

        Thank you very much.

  17. Libor

    Hi Laurens

    I have a problem with variable speed. If I have in code loop


    robot dont go straight.

    but if I write


    for example. Robot normaly play sound.

    Please help me with variable speed. Is variable speed for control motor?..


    1. maximurx

      Hi Libor, this is a problem related to newest RobotC or drivers. Laurens is already looking at it. In the meantime switch back to RobotC 3.08 or similar …

      Laurens: Can you tell us where to find the related drivers ?

        1. Brian

          There is a bug in RobotC 3.51 that should be fixed in the next version. In the meantime, you can use this workaround in segway-driver-lv.h:

          Change line 199 from
          v = v + acceleration*10*dt;}
          v = v + acceleration*10.0*dt;}
          Also do similar on line 201 – change 10 to 10.0

  18. Syed

    Hello Lauren,
    I’m just a begginer with RobotC program. I’m learning. Could you just help me what part of your program will just make the robot stay still, in other word what part of your program will make the robot just balance itself.
    task main()

    would this do it?

  19. Barry

    Hi Laurens,

    thanks for your very clear tutorial!

    I have a question: do you think it would be possible to have the robot balancing without using the NXT motor encoder positions? I’m thinking about applying this method to another type of robot that does not have these encoders..

    Thanx in advance for your reply!


    1. Hi Barry,

      Glad to hear you liked this project. I think it can be done, but simply removing it from this code might not work. You could try by setting gn_th and gn_dth_dt to zero. This effectively cancels everything that’s done with the encoders in terms of balancing.

      Then you can try adjusting the other gn values and the kp, ki, kd, to see if it can still balance.

      Alternatively, you could create some sort of variable that integrates the speed, thereby providing a rough position without encoders.

      Let me know how it goes.



  20. Sakthi

    I tried the first program (using all the defaults; with NXT 2.0 wheels of Ø42), and all it drives the robot reverse for a second and stops. I tried to keep the robot upright and pressed the orange button as said in the instruction. but it fails. Does the program works in NXT 1.0 kit?
    I am pretty sure that I followed everything as advised. I am using HiTechnic Gyro sensor. I did commented the other sensors everywhere in the program. But still it doesn’t balance. Could you help me on this?

  21. Demetri

    Hi Laurens
    I am having some problems with the code. It is giving me these errors:
    *Warning*:Unreferenced variable ‘Gyro’
    *Warning*:Unreferenced variable ‘your_wheel_diameter’
    **Severe*:Couldn’t open ‘#include’ file ‘drivers/dexterind-imu.h’
    **Severe*:Couldn’t open ‘#include’ file ‘drivers/microinfinity-cruizcore.h’
    **Severe*:Couldn’t open ‘#include’ file ‘drivers/mindsensors-imu.h’
    **Severe*:Couldn’t open ‘#include’ file ‘segway-driver-lv.h’
    **Error**:Undefined variable ‘balancing’. ‘short’ assumed.
    **Error**:Undefined variable ‘starting_balancing_task’. ‘short’ assumed.
    I’m using the dIMU and RobotC trial . Also, I am new to RobotC so this all confusing, is there a way that you could make the NXT-G anyway program work with the dIMU?

    1. Hi Demetri,

      It looks like you have not unzipped your code correctly. Your program and the “segway-driver-lv.h” are not in the same directly. Also, you haven’t properly installed the sensor driver suite.

      It can’t find several files that it needs to compile the program.

      Please try to fix these two problems and let me know how it goes.


  22. firecannons

    I’ve tried to make some make some programs for a blancing robot from scratch and they haven’t worked. My dad followed the tutorial and sucessfully got the balancing segway. Now, I’m trying to do it with tetrix. Do you know if you have make a tetrix version of the program? Would substituting motorE and motorD(the tetrix motors) for motorB and motorC and changing wheel size make it workable for tetrix?

    1. The Tetrix motors have very different dynamic properties. You may be able to use the overall program structure, but some modifications would be needed. If you study the program and how it works with NXT, you may be able to make changes and make it work with Tetrix. I do not have a Tetrix system.

      1. firecannons

        I’m still trying to get this to work with tetrix. The only large programming change with hte tetrix is that they don’t have built in incoders and I haven’t bought extra ones. Is there a way to get it to balance without encoders? I see that encoders are used a lot.

  23. Chris

    Amazing set of sample code and it all works first time!
    I would like to go on to design a bicycle that balances by steering into a fall. How difficult do you think the PID control will be, compared with the segway?

  24. Matteo

    I’ve tried this project with the Gyro Mindsensors but nothing. When program start, no balancing, motors start reverse for one second and then program aborted. I’m sure to following instruction, my sensor is new (2012 december) where i fail? Please help, thanks

  25. Kazuo

    Hi Laurens,

    I’m grateful for your wonderful tutorial.

    I am happy because it is very easy to understand written header file.
    By the way, why do you have to take n_max = 7 in your header file?
    Do you have related to the time of each loop?

    1. Hi Kazuo,

      Thanks for your feedback. The program saves the 7 (n_max) last measurements of the rotation sensor. Then, it can compare the current rotation sensor value with the one measured 7 loop runs ago. Then (New – Old) / time elapsed gives the speed of the motor.


      1. Kazuo

        Hi Laurens,

        Thank you for the answer. The motor speed is certainly calculated by using n_max(number of arrays) as you say.
        However, the number of arrays of 7 pieces is in inverse proportion to the motor speed.
        What is the reason why you chose the value of n_max to be seven in the meantime?

        1. The number 7 is a choice (trial and error) between a smoother average (higher number) and a more recent value (lower number for n_max).

          A low number may result in spikes that cause unexpected behavior. In a single loop (n_max would be 1), the motor rotates only a little, sometimes not at all. This provides an inaccurate velocity measurement.

  26. Hanumant

    Hi Laurens

    Thank you for the wonderful instructions. I plan to use these soon.
    I was going through the code. It seems you treat dy/dt as angular velocity, wouldn’t this be the linear velocity?
    Could you give some background on how the equations are arrived at?


    1. Hi Hanumant,

      The difference would be a constant factor, namely the wheel radius. I think I have that in the code, but I might be wrong (I’m unable to check it at the moment).

      I used the thesis listed at the end of this blog post.

      I wrote this code more than three years ago. With an engineering degree soon, I need to go back and rethink the dynamics some day. It’s on my to do list 🙂


      1. Hanumant

        Cool good luck with the degree. BTW i tried all your instructions and standard configuration. But I see after the callibration done, when I press the orange button, the mottor spins for a while and the segway falls over. I have verified connections B and C as well as sensor. Just one question, this might be very dumb, but for the intial calibration am I supposed to put the segway flat on its back or hold it upright. What should be the approx mean value?


        1. From your comment I’m assuming you’re using the HiTechnic Gyro, correct?

          During calibration, the robot must be held still. This is done by putting it on the floor (as per the on screen instructions), or by holding it upright, but completely still.

          You’re looking for a value somewhere between 550 and 650. 0 or 1023 would indicate a disconnected cable.

      2. Leiliane

        I’ve only had problems when the briteates were extremely low. The control system will compensate for any changes in motor drive. The placement of the acceleromenter is critical. If you think about it from a physics perspective, the position at which you will get the most precise reading from the acceleromenter is if it is placed at the axis of rotation (of the system, NOT the wheels! Ie. When the system is trying to balance, it is the spot that receives the least amount of movement). If it is placed far from the axis of rotation, then things such as centripital force and/or readings from falling will make the readings inaccurate. The gyroscope however, since it is a mems device, should be fine placed anywhere.Tell me how it goes.-J

  27. Dani

    Hi Laurens,

    I’ve same problem with Mateo to balance the bot, it keep reversing and aborted,
    I use mindsensor imu acg, lates updated robotc 3.6.1 and driver suite 3.1.1
    Mateo said drivers corrupted, but which driver?
    All program running well unless the bot keep falling down
    Any idea how to fix it?

  28. Greg

    I just bought the Mindsensors digital gyro sensor and for my first project I’ve built your segway model. I’m trying to convert your NXT-G code to this sensor and am having some problems. When I run the program the model tries to move forward at a high rate of speed and it falls backwards. I’ve verified that I’m reading the correct axis. Besides changing the sensor block, I’ve changed the various PID variable values to match what is shown in the Mindsensors modified version of your Robotc code. I’ve made no changes to the custom control task loop. Any ideas? I do write in C/C++ but don’t have Robotc, would porting the code to NXC be a better idea then using NXT-G?


  29. Treesa

    When this program is used for balancing my lego balances for 2sec and then stops responding and it start responsing again..I think the problem is with
    switching motorpower between + and – in 10ms..What shoul i do??PLease help…

  30. Adam

    im sure that the driver suit is installed correctly, and i still have this error : *Warning*:Unreferenced variable ‘Gyro’

  31. marc

    Hello, I have an acelaration sensor and, if posible, I don’t want to buy de gyrosensor. I spent a lot of time trying to do the selfbalancing segway but I haven’t been able. I know it is posible but I don’t know how to do it.
    Could you help me? How can I do it?

  32. Dennis Harris

    Hi Laurens,

    Great work on the Segway robot, it’s become the basis for my HRI work.

    I’m trying to get the robot to balance in place for a set time, then drive forwards a set distance, then balance in place until I pick it up to terminate the program. My programming skills are currently limited, is there a way to insert these commands into the following program?

    Thank you again for everything you do! My work wouldn’t be possible without it.

    task main()
    //Start balancing and wait for configuration to finish

    gn_dth_dt = 0.23;
    gn_th = 25.00;
    gn_y = 272.8;
    gn_dy_dt = 24.6;
    kp = 0.0336;
    ki = 0.2688;
    kd = 0.000504;



  33. Cody

    Hi! How do you fixed the offset of the gyro?
    I think you correct that in this line:”mean_reading = mean_reading*0.999 + (0.001*(dth_dt+mean_reading));”. But can you explain me exactly what this does?
    Other thing is in this line: “encoder[n] = nMotorEncoder[motorB] + nMotorEncoder[motorC] + y_ref;”. Why do you add both encoders values to get the position and not only use one? I mean if the encoder B says 40, the encoder C probably will say the same thing.

    1. Hi Cody,

      By calculating the long time average (mean_reading), the changing sensor offset can be compensated for. This is better documented in the reference linked to.

      “Why do you add both encoders values to get the position and not only use one?”

      I take the average, so that the effect of turning is ignored. When the robot stays in place, the average encoder value stays the same.

  34. sara

    COM_CloseNXT all;
    h= COM_OpenNXT (‘bluetooth.ini’);
    COM_SetDefaultNXT (h);
    mB=NXTMotor ( ‘B’);
    mC=NXTMotor ( ‘C’);
    mB.Power = 10;
    mC.Power= 10;
    mB. SendToNXT();
    mC. SendToNXT();
    OpenNXT2Color(SENSOR_2, ‘FULL’)


    if strcmp(c,’WHITE’)

    mB.Power = 10;
    mC.Power= 10;
    mB. SendToNXT();
    mC. SendToNXT();

    else strcmp(c,’BLACK’)

    mB.Power = -10;
    mC.Power= -10;
    mB.TachoLimit = 300;
    mC.TachoLimit = 300;


    else strcmp(c,’BLACK’)

    mB.Power = 10;
    mC.Power= 0;
    mB.TachoLimit = 440;
    % mC.TachoLimit = 0;
    mB. SendToNXT();
    mC. SendToNXT();


    else strcmp(c,’GREEN’)


    COM_CloseNXT (h)

    can you please tell me what is wrong with this code, i need it to walk throw a maze.it keep telling me that there is an error in else statement.i am using 2013 version of matlab.

  35. Joh

    In balance mode, robot creeps forwards slowly (each forwards corrective movement is larger than each backwards corrective movement). Has anyone found a fix for this?

  36. Weichen

    I am using HiTechnic Gyro.
    But when I use “NoAction”, Segway is reversing always, although it can upright.
    I do not know what the parameter have a problem.
    Parameters of PID or Parameters of GN ???

  37. Henry


    Could you explain this section of code? I know what it is supposed to do, but I’m not sure exactly how it works.

    n++;if(n == n_max){n = 0;}
    encoder[n] = nMotorEncoder[motorB] + nMotorEncoder[motorC] + y_ref;
    n_comp = n+1;if(n_comp == n_max){n_comp = 0;}
    y = encoder[n]*degtorad*radius/gear_down_ratio;
    dy_dt = (encoder[n] - encoder[n_comp])/(dt*(n_max-1))*degtorad*radius/gear_down_ratio;

  38. Dan

    Hi Laurens,

    I’ve followed the tutorial so far and tried to run the segway no action file. It compiles fine although there are warnings about spelling and letter case. However the code does nothing and aborts immediately.

    I started the code with the robot laying down, then stand it up and press the button, which is when it aborts immediately. I have also tried to calibrate from an upright starting position, with no difference in results.

    I have installed the latest driver (3.3.1), I also tried the 3.1 driver suite, neither worked. My robotc version is 4.50. The F/W version is 10.50


  39. Andre Ghiorzi

    Hi Laurens!
    First of all, thanks to all your help by sharing your knowledge with us!
    It will be very kind of you on answering a question: dou you think it is possible to program the Balancing Robot using the Mindstorm conventional platform instead of RobotC? If you say yes, me and my 14 years old son will dedicat as many time as nedded to do so!
    Thank you in advance!

Leave a Reply


EV3 Discovery

Discover the many features of the EV3 set, and learn to build and program your own robots! Learn more

Start Building Robots


Website Maintenance

Robotsquare is currently being updated, which means that it may look a little different (and not very polished) for a while. All the content and pages should still be there, though. It should be back and fully operational soon. Thanks for your patience!