High speed balancing robot: introduction

By | November 10, 2018

For quite some time, I’ve been developing a two wheeled balancing robot. You know, like a Segway. But in this case it is somewhat smaller, as to minimise damage when hitting something at high speed. That happens rather often, due to the very high maximum speed of this robot.

This post will cover the architecture of the robot, explaining all ins and outs. Many balancing robots have been made before, but this one has some nice features that make it very well behaved. Also, everything has been designed to make the robot easy to replicate. As one of the goals of this project is to get other people to work on the robot, all source files will be made open source. Also, in a future post I hope to document how to build one.

Just to be clear: the purpose of me making this project open source, is not for people to get such a cute, fun robot, that they’ll play with and then never use anymore. The purpose is to educate other people, to share knowledge, and to create and extremely good performing robot together. Just because. Because developing technological things without purpose is fun.

Basics

In order to balance an unstable system, negative feedback is required. The diagram below illustrates the approach. Besides a feedback loop, a sensor to measure an error (or rather the sytem response), and an actuator to minimise the error, are required.

Sensing and actuation

Getting a sensor with sufficient accuracy and bandwidth is relatively easy; in this case the well-known (and mostly cheap) MPU6050 IMU is used. The accelerometer provides a long term stable, but noisy signal, especially if you accelerate fast. The gyroscope on the other hand gives an accurate, high speed signal, with drift however. Combining the two using a simple complementary filter gives a stable signal, representing the angle of the robot.

Next, an actuator needs to be selected. A common choise is a DC motor, for example for its low cost or simple control. However, a DC motor has in general a too low torque to directly drive the wheels of the robot. A gearbox is used to increase torque, but several disadvantages are introduced as well. Cheap gearboxes have severe backlash and friction, which make the control loop non-linear, and therebey making everything a lot more complicated.

This is where the stepper motor comes in. This idea isn’t new, serveral other examples of balancing robots with stepper motors are available. For some examples, see herehere or here. Steppers are quite suitable for the job: direct drive, relatively high torque, low inertia (which isn’t true for a DC motor with high gear ratio), and no backlash. Stepper motors are commonly used in for example 3D printers, and can hence be found for a low price (about €10 each). Driving the steppers is also done with 3D printer related parts. A so called step stick, containing a DRV8825 IC, arranges all the power electronics, accepting a logic step and direction input.

Software

Then comes the software. In my opinion, this is the part where the most difference can be made. The above description holds for a lot of balancing robots. With suitable software / control implementation, a lot of differentation can be made. The software of this robot runs on an ESP32, a dual core microcontroller with integrated WiFi and Bluetooth. Using an ESP32 allows for several nice tricks, such as control with a smartphone via WiFi / Bluetooh (not implemented yet), OTA, wireless data logging, etc.

Currently, the software runs two control loops at 200 Hz. See below for a schematic view of the two (cascased) controllers. The first control loop tries to minimise angle error, i.e. keeping the robot upright (in case of a zero reference). The second control loop either controls position or speed, depending on user input. If no input is present, position is regulated to be zero. Otherwise, the outer controller manipulates robot angle to obtain a speed equal to the speed setpoint. To give an example: if the robot is standing still, and a positive (forward) speed setpoint is given, the robot tilts forward until it reaches the desired velocity. When standing upright, the inner control loop moves the wheels backwards, such that the robot will tilt forward.

Electronics

For powering the robot, I currently use a 6S1P (24 V) 2650 mAh LiPo battery. That’s quite a big one: it allows for up to 5 hours of driving time. So, such a big battery is not strictly required. Besides this battery being relatively cheap (in Wh/€), a big mass on top of the robot makes the robot fall “slower”. This makes stabilising the control loop easier, and, it also looks more natural in my opinion. A sturdy case has been 3D printed to fit tightly around the battery, to allow for protection. The high voltage of the battery allows the steppers to be run at extremely high speeds. Note that 6S is over the top, and 3S will give sufficiently high speeds.

The last part to add is a PCB. For the first robot versions, I developed some experimental PCBs. For the current version, I’ve drawn a simple PCB, based on commonly available modules (IMU / step-stick / ESP32 dev board), which allows for easy assembly. The PCB is drawn in KiCad, which is open source software. In case you want to make something yourself (on an experimental PCB), see the PDF of the schematic in the Git repo.

Some PCB history

The total cost of the robot is quite limited due to use of standard components. Electronics are about €10, steppers €10 a piece, battery between €5 and €30. The frame can be printed cheaply (see Git repo for source files), or simply zip tie everything to a piece of wood. Currently I use an RC transmitter / receiver, which drives the cost up, but as soon as WiFi/Bluetooth control is implemented, it isn’t required anymore.

To end this post, some more pictures of the complete robot(s). Yes, it has a small brother :).

More info

Source files can be found in the Git repo. It is highly appreciated if you contribute to the project!

The subolders in the repo also contain readme files, explaining how to assemble the electronics, and how to setup the software environment.

59 thoughts on “High speed balancing robot: introduction

  1. Hank, LEE

    Hello.

    I saw your high speed balancing robot in youtube.
    it is interesting for me and I want to do this project if you let me. ^^

    Could you send me a PCB ( current version )?

    Now i am buying resource motor and etc.
    Thanks for your video.

    Reply
  2. ROBERTO CARLOS DA SILVA ALVARENGA

    Hi ! Congratulations!!!!
    I really like your project! And I want to do the same.
    What is the model of the motor stepper that you’re using ?

    Thank you.

    Reply
    1. Wouter Post author

      Thanks for your reponse! I use Nema17 stepper motors (the ones typically found in a 3D printer). I’ve used motors with a length of 34, 40 and 48mm, all work ok. I think 40mm length is a nice balance between weight and torque required for this application.

      Reply
    1. Leonardo

      Friend excellent project. I’m mont one together for my son. I installed Atom but in the compilation it presents errors. Did you need to install any external libraries?

      Reply
      1. Wouter Post author

        Hi Leonardo, thanks for your response! I think your error is caused by me not having included the Streaming library; I installed this library globally (which is bad practice). See the latest commit in the dev branch: https://gitlab.com/kloppertje/balancingrobot/tree/devel

        If it still doesn’t work, please post (or better, mail) the specific errors you get. Also, I can recommend VSCode, it works a bit better compared to Atom with PlatformIO, in my opinion.

        Reply
        1. Leonardo

          lib\AsyncTCP\src\AsyncTCP.cpp:259:27: error: field ‘call’ has incomplete type ‘tcpip_api_call’

          Reply
          1. Leonardo

            I solved the error above. I upgraded the AsyncTCP library to 1.0.3 now I’m having this error. lib\I2Cdev\I2Cdev.cpp:276:75: error: no matching function for call to ‘min(uint8_t&, int)’

        2. tophe

          no matching function for call to ‘fastStepper::fastStepper(int, int, int, bool, void (&)())’

          Reply
  3. Leonardo

    Friend excellent project. I’m mont one together for my son. I installed Atom but in the compilation it presents errors. Did you need to install any external libraries?

    Reply
  4. AMF

    Hi, exccellent Job!, i try build it, but when build the project on platformIO show this error in I2Cdev.cpp:
    “no matching function for call to ‘min(uint8_t&, int)’
    In Line 276:
    for (uint8_t k = 0; k < length; k += min(length, BUFFER_LENGTH)) {

    Any Idea?

    Thanks!!!

    Reply
  5. Robert

    Hello,

    congrats to your cool project and thanks for sharing it! I have onestion: which polyfuse (how many amps) did you use?
    Do you have a pcb left for sale?`

    regards

    Robert from Austria

    Reply
  6. Robert Schossleitner

    Hello Wouter,

    thanks for the PCB. Now i am fighting a bit with the Stepper Code in the Loop i found this lines.

    motLeft.update();
    motRight.update();
    // updateStepper(&motLeft);
    // updateStepper(&motRight);

    In my case it seems that ust the motLeft produces an appropriate stepper clock on the gpio pin the motRight gpio is quiet. However the direction pin of the motRight is working. If i flip the update-Statements (motRight first), in all cases the first is working. It seems to me that something with the timer/ISR is not working. Do you have any hints regarding that problem?

    BR Robert

    Reply
    1. Wouter Post author

      Hi Robert,

      I haven’t experienced these issues before. Are you using the devel branch (which I recommend)? And, have you changed any of the pins used for step generation? Maybe something goes wrong in this function (lib/fastStepper.cpp):
      void IRAM_ATTR fastStepper::timerFunction() {
      // portENTER_CRITICAL_ISR(&timerMux);
      if (!pinState) {
      _step += dir; // Step is made on rising edge
      GPIO.out_w1ts = 1<<_stepPin; pinState = 1; } else { GPIO.out_w1tc = 1<<_stepPin; pinState = 0; } // portEXIT_CRITICAL_ISR(&timerMux); } You could for example try using digitalWrite (which is probably a bit slower). KR Wouter

      Reply
    2. Atilla BALCI

      What type fuse should i use instead of F1 polyswitch? i can’t find it in my country. Ampere or volt?

      Reply
      1. Wouter Post author

        Depends on the supply voltage. Typically, two stepper motors consume 10-15W. So, at 12V that’s roughly 1A. So, a polyfuse with a rated current a bit above that, say 2A, should suffice. And the rated voltage should then be higher than 12V. But again, it all depends on the choice of input voltage.

        Reply
        1. Atilla BALCI

          I am trying to do the same as yours. Will work with 6s lipo. How many volts and amps do you recommend? There are thermal and glass fuses with legs but I don’t know how many degrees Celsius or amperes (volts) i will use.

          Reply
        2. Atilla BALCI

          Finally, I am confused about two points.
          First, in the pcb readme file, you said “You can de-solder the current adjustment potentiometer on the stepper driver breakout boards. Add a wire to the wiper terminal, and connect the (two) wires to J4”. As far as I understand, J4 and J7 for the stepper motors output connections. Will the cables from the stepper driver breakout boards be connected to J4 or J1?
          The second is JP1. I tied the decay mode pin of the DRV8825 to VCC. Will JP1 tips be soldered?
          Thank you for your support.

          Reply
  7. Robert Schossleitner

    Hello Wouter,
    yes i am on the devel branch. I have written an alternative loop-function with just a simple test code in it. And i am counting how often the IRAM_ATTR motXXXTimerFunction() are called.

    https://github.com/SrR0/BalancingRobotESP32/blob/master/src/main.cpp

    The counter of the left motor interrupt is counting up the other stays 0. If i flip the first

    motLeft.update();
    motRight.update();

    to

    motRight.update();
    motLeft.update();

    the right motor output is working. The Timer and portMUX stuff is a bit suspect to me. It seems the first timer functioncall is locking something with the timer of the other motor

    BR Robert

    Reply
  8. Robert Schossleitner

    Hi!

    in the meantime i found out that if I disable the timer before enable it, it seems to work. So the second timerAlarmEnable without timerAlarmDisable before does not work. I have no idea why.
    fastStepper::update(){

    timerAlarmDisable(_timer); //just for testing todo: cleanup
    timerEnable = 0;
    if (!timerEnable) {
    timerAlarmEnable(_timer); // Re-enable timer
    timerEnable = 1;
    }
    } else {
    timerAlarmWrite(_timer, 100000, true);
    timerAlarmDisable(_timer);
    timerEnable = 0;
    }

    BR Robert

    Reply
  9. Robert Schossleitner

    Hello,

    I used the PID controller class in a different projekt and I noticed that the behaviour when using the integral term of the PID controller was a bit weired. The lower I set it, the more powerful was the effect. I didnt understand the calculation oft the integral term:

    void PID::updateParameters()
    {
    _if = _dT/Ti;
    _df1 = Td/(Td+N*_dT);
    _df2 = Td*N/(Td+N*_dT);
    }

    the higher the Ti ist the lower is the effect when being multiplied with the error of the comparation between setpoint and feedback-input.

    I changed it into
    void PID::updateParameters()
    {
    _if = _dT*Ti; //higher value of the Ti and longer sampleperiode should increase the effect of an error

    _df1 = Td/(Td+N*_dT);
    _df2 = Td*N/(Td+N*_dT);
    }

    Seems to work for me. Maybe I did not understand the whole therory 🙂

    BR Robert

    Reply
    1. Wouter Post author

      Hi Robert,

      This is just a matter of definition. Sometimes people use “gains”. I like to look at the PID controller in the frequency domain, and in that case using time constants (Ti and Td) makes more sense. A lower Ti means it will work up to a higher frequency, i.e. it will be more aggressive. The same goes for Td, a lower time constant means a higher frequency at which the damping action is active. So, in this case, a higher Td gives the feeling of “more damping”, which probably is a bit more intuitive than the behaviour of Ti.

      KR,
      Wouter

      Reply
  10. Atilla BALCI

    Hi,
    I am tryng to open pendulumRobotModule.sch on Eagle. But it gives me this error and not opening.

    Loading C:/Users/ati/Desktop/Hızlı robot/balancingrobot-master/PCB/pendulumRobotModule.sch …
    Error:
    line 1, column 1: Start tag expected.

    Reply
  11. Atilla BALCI

    hello, i want to make one. do you please send me the board if it possible?

    Reply
  12. Dave Waldesbühl

    Hi Wouter
    First of all a big thank you for sharing this project! I’m building one. So far everything is OK. But I have two places in “main.cpp” which I do not understand and which platformIO shows as faulty.
    Source: https://gitlab.com/kloppertje/balancingrobot/-/blob/devel/Software/src/main.cpp

    1. In line 524: plotData; -> “The default constructor of” “union ” “cannot be referenced”

    2. in line 718: accAngle = atan2f ((float) ay, (float) az) * 180.0 / M_PI – angleOffset;
    -> “M_PI” is not declared or otherwise referenced. What is that value?
    Best regards
    Dave

    Reply
  13. Atilla BALCI

    Hi Wouter,
    I have built one working with 24v and its working excellent. But i can not activate the servo. Could you help me?

    Reply
  14. Jerry Wenzel

    Hi Wouter,
    Great build. I love the speed & stability.
    Do you still have PCB’s available? I’m in the US. Is there a way I can pay you for the PCB & postage?

    Also, I have 38mm NEMA17s. You had mentioned a 42mm being good for torque. I take it the lower torque would affect higher speed operation but would be OK at lower speeds?

    Dankjewel!

    Reply
  15. Baur

    Hello! Your robot does not lose balance if it is tilted left or right?

    Reply
    1. Wouter Post author

      Depends on the orientation you’d be pushing in. And if you push hard enough, it’ll fall. It can handle some slight pushes though.

      Reply
  16. Owen Williams

    Thankyou for your excellent design. It works really well. I’ve been looking at your code and have learnt a ton of neat tricks e.g ota flashing, ibus, mulicore coding, and was shocked that you even have a html editor tucked on board!
    Not sure whether this comment system will allow me to put a link to a YouTube video, here goes:
    https://youtu.be/_oza35BNgYA
    I do love the esp32. Where did you learn about spiffs and mdns. Totally new to me!

    Reply
  17. Henk Rieuwers

    Hi Wouter, i have error 404 when i try to connect ip adress 192.168.4.1.
    on the terminal from platformio the message: Loading index.htm.
    What could be the reason? the build is without errors.
    greetings, Henk

    Reply
  18. Wilbert

    Hi, i built this project and it was awesome. Thank you!!
    It felt nice seeing the robot balance for the first time.
    I did some modifications though due to different hardware available to me-> stepper driver changed to tmc2208 witj UART control and currently im working on a bluetooth joystick control from an android app. encountered a problem on program size due to addition of serialbluetooth library but i think i can make it work after modifying the esp32 partitions.
    I got some questions on the Ibus input range. Is it from -1500 to 1500 for the speed and steer?

    Reply
    1. Wouter Post author

      Nice to hear that you can make use of the hardware/software! How do the TMC drivers work? Does it give a smooth/silent response?

      IIRC IBus variables are in the range of 1000 to 2000 (so similar to PPM, which goes from 1000 to 2000 us, I think).

      Reply
  19. Andrew Smith

    Awesome model! There’s a few self balancing robots to watch on YouTube. Yours is clearly much quicker that the rest and is super smooth and responsive, so what makes the difference? Those thin wheels on a hard surface? Using an ESP32 as opposed to an Arduino which is what most people use? I wondered about using the 6S battery but the NEMA 17s only run 2.8V so I’m assuming it’s not that. Or is it the pure weight of the 6S cell that helps? A combination of these things? What’s the secret?

    Reply
    1. Wouter Post author

      Thank you! Difference: a lot of time invested in the project, I guess :). And some thought put in the control process. I think the main influence is the actuator: the steppers have almost no backlash, low friction, and respond (up to a certain frequency) well to the command given. Also, the robot only works well on flat surfaces. Due to the limited torque of the steppers, not much disturbances can be handled. And btw, “performance” could be way better, e.g. by tuning in the frequency domain, or by using a better actuator (brushless / PMSM motor). But that would require encoders and FOC, which would make the project much more complicated (and expensive).

      About the battery: the steppers have a rated voltage of say 2.8V, but this is purely the I*R component (i.e. resistive). The stepper driver works as a buck converter, so it just converts the high voltage to a lower one. Also, at higher speeds, you’ll get (lots of) back-EMF, hence the battery with the high voltage. Although, in general, 3S would be sufficient I think.

      Reply
  20. David Stewart

    Great stuff man.
    Have most the parts already. Missing parts on order, ✓
    I sent your PCB design to get made. 3 on the way, ✓
    Had a couple issues with dependancies in the code but tracked down issues and it’s all uploaded to the ESP32. ✓
    I had to grab a modified i2cdevlib for anyone running into compiler errors with main branch, take a look at: https://github.com/jrowberg/i2cdevlib/pull/530/commits. It worked for me. ✓
    I can’t wait to get into this!, I have ideas…. I will report back ( ͡° ͜ʖ ͡°)
    Thanks for all the great info
    Cheers.

    Reply
  21. Fasstoch

    Hello !
    I’m just a beginner in electronics and I’m looking for a two wheels robot as a first project to learn.
    Yours looks really nice ! Responsive ! Fun ! 🙂 congrats ! I love it 😻
    I’d like to do the same if you allow me 🙂
    Sorry in advance for my newbies’ questions …
    Have a 3D printer for body, wheels, … and an Amazon account ^^ for electronics but I don’t know anything about PCB :/ you created your own one !? I can’t do that 🙁 can I use something else ?
    Very thanks for your sharing.
    Cheers

    Reply
  22. Sebastian

    Hi Wouter,

    I built “mine” from recycled parts (CNC shield, NEMA 17 steppers from a dead 3d printer) and the chassis from “Fischer Technik”, a kids building blocks toy system.

    After taking much too much time before finding out that the “enable” pin needes to be pulled up, it now works like a charm. Also, I didn’t manage to set the PID right for the Fischer Technik wheels, so I printed yours and it works even better.

    Thank you SO MUCH for publishing your awesome code and sharing the CAD files! It seems the steering via websocket is deactivated and I received only errors when trying to “revive” it by uncommenting the relevant sections.

    So, I implemented my own steering code; it looks so crude next to yours.

    However, it works and my kids love to play with the bot.

    Again, a big thank you and all the best-
    Sebastian

    Reply
    1. Wouter Post author

      Hi Sebastian, nice to hear that you are tinkering around. Have fun!

      Reply
  23. Tobi

    Hi Woulter,
    thanks for the excellent code!
    I am currently working on changing the suspension axis so that it can easily overcome small steps and thresholds. Like in this video:

    https://www.youtube.com/watch?v=gs_H3TOrLxw&feature=youtu.be&ab_channel=RobotEnthusiast

    I already tuned it and it can drive and it also manages small thresholds. I would just like to make it so that he does not lean forward when he drives forward. Is this possible and if so where do I have to start?
    Thank you very much

    Reply
    1. Wouter Post author

      Hi Tobi, I’ve seen the video before and it’s quite an intriguing approach. “Basically” it’s just a double pendulum, of which many examples can be found on youtube; a double pendulum can be made stable by means of feedback control. The new thing with this robot is that there is a belt drive between two axes of the double pendulum.

      Where you start depends on what you want to achieve. If you want to fully grasp the system, develop system dynamics and simulate the system etc. I think it’d be wise to make some sketches first, to get a feeling of what’s happening. At the moment I don’t have intuition for this robot and I don’t want to get involved in it. But you could for example sketch torques/forces on the wheels/link/main frame in various positions: when the robot is standing upright with the link vertical, or when the robot is upright with the link horizontal. Just fiddle around and get a feeling for the system. Or, look up the paper :). I believe there’s a paper on the web somewhere. Ah found it: https://ieeexplore.ieee.org/abstract/document/6631384

      Reply
      1. Tobi

        Hi Walter, thanks for your answer. I think I did not express myself clearly. I have already rebuilt the axis and experimented with several gears and belts and I have the robot so far that it stands straight and can climb small steps. https://vimeo.com/515034525
        The only problem is that it tilts over at higher steps. I think it is possible to compensate the tilt via software. I will do more research on the double pendulum and look deeper into it.
        Thanks for the hint! If I have a useful result I will write it here.
        Thanks a lot!

        Reply
    2. Wouter Post author

      Very cool! Design looks also nice and clean. I shared your video with some people as I’m quite fond of the concept and your execution :).
      Hmm let me think. Should indeed be possible to correct for tilt, but the control parameters will be very different as the wheels are blocked. Basically you’ll be moving the lower link to keep the upper body upright. My intuition says you can only keep the robot stable if the lower link is mostly vertical. If it were horizontal, you could change the angle of the lower link but the upper body will not move horizontally i.e. the system is not controllable.
      If controller parameter switching would indeed work, the trick is how to detect (quickly) if the wheels are blocked. Maybe it would help if you add another IMU in the lower link? If you’re good with controller design you could also use this to prevent the high frequency oscillation you sometimes see in your video.
      Also, if you want to play around maybe it would help to simulate. Last week I was playing around a bit with Matlab / equations of motion and animating the result. Let me know if you speak Matlab 😉
      Also, maybe it’s better to continue (if you like) via e-mail? wouter@elexperiment.nl

      Reply
  24. Charles

    In 2003, I saw a video of nBot. It was a two wheel self-balancing bot. I wanted to make one so bad. Never got around to it. A few months ago I saw your video and said to myself, “DO IT!”.
    I had a spare ESP32-DEVKITC-32D so I went with that. Modified your schematic for the different pin outs and made a board. Today, I soldered the ESP32, MPU-6050 and the DRV8825. After calibrating the Gyro and Accels ( making sure the motors rotated in the right direction) it balances! I am so very pleased! I need to add the RC control, battery monitor and maybe distance sensor.
    Thanks

    Reply
  25. Robert Reed

    Hello Wouter!

    I have been researching many different two wheeled balancing bot designs and yours is by far my favorite! I have a number of parts on order and am starting to print the files you have shared. I am curious, what did you use for the tread on your wheels? It looks like you may be using a large rubber o-ring. Is that correct? Can you provide dimensions? Did you try printing a tread with flexible filament?

    Cheers,
    Robert

    Reply
    1. Wouter Post author

      Hi Robert,
      Sorry for the late reply, apparently I missed something. Indeed, I use O-rings, diameter is 80mm (for the smaller wheels) and 110mm for the larger ones. I haven’t tried flexible filament, as the O-ring solution works quite well (if I vacuum clean so now and then, otherwise the robots start drifting :)).

      Reply
  26. Gabriel Pineda

    Hello, how are you? I congratulate you, excellent project. I’ll tell you, I did it and it works very well, it keeps the balance, I push it and it stands up, but I have a problem. I bought a 6-channel RC FS-i6X and when the robot is connected it loses its balance and falls and I’m sorry I’m not an understanding in the art of programming I just really like electronics as a hobby if someone could help me solve this problem I will be very grateful

    Reply
    1. Wouter Post author

      Thanks for the appreciation, and good that you could make use of the code! Did you try setting the robot upright manually after connecting the receiver? Also, have you tried the latest devel branch (instead of master)? If these two things don’t help, you can “debug” by placing serial print commands at tactical places in the code, so that you can learn why the robot doesn’t work as you want it.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.