{"id":28999966,"url":"https://github.com/ripred/tomservo","last_synced_at":"2025-06-25T08:41:12.612Z","repository":{"id":59977699,"uuid":"490568500","full_name":"ripred/TomServo","owner":"ripred","description":"Sophisticated Servo Power Management for the Discriminating User","archived":false,"fork":false,"pushed_at":"2025-02-01T04:06:27.000Z","size":84,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-01T05:18:38.042Z","etag":null,"topics":["arduino","arduino-library","attach-detach","battery-power","embedded","esp32","low-power","micro-controller","microcontroller","motor-drive","multiple-servos-one-battery","power-conservation","power-management","pulse-width-modulation","pwm","servo-control","servo-power-managmenent","servos"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ripred.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ripred","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2022-05-10T06:25:59.000Z","updated_at":"2025-02-01T04:06:31.000Z","dependencies_parsed_at":"2025-02-01T05:28:26.365Z","dependency_job_id":null,"html_url":"https://github.com/ripred/TomServo","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/ripred/TomServo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ripred%2FTomServo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ripred%2FTomServo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ripred%2FTomServo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ripred%2FTomServo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ripred","download_url":"https://codeload.github.com/ripred/TomServo/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ripred%2FTomServo/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261838334,"owners_count":23217616,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","arduino-library","attach-detach","battery-power","embedded","esp32","low-power","micro-controller","microcontroller","motor-drive","multiple-servos-one-battery","power-conservation","power-management","pulse-width-modulation","pwm","servo-control","servo-power-managmenent","servos"],"created_at":"2025-06-25T08:41:10.905Z","updated_at":"2025-06-25T08:41:12.596Z","avatar_url":"https://github.com/ripred.png","language":"C++","funding_links":["https://github.com/sponsors/ripred"],"categories":[],"sub_categories":[],"readme":"\u003c!-- [![Arduino CI](https://github.com/ripred/TomServo/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci) --\u003e\n[![Arduino-lint](https://github.com/ripred/TomServo/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/ripred/TomServo/actions/workflows/arduino-lint.yml)\n![code size](https://img.shields.io/github/languages/code-size/ripred/TomServo)\n[![GitHub release](https://img.shields.io/github/release/ripred/TomServo.svg?maxAge=3600)](https://github.com/ripred/TomServo/releases)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ripred/TomServo/blob/master/LICENSE)\n\n# Thomas Servo Eskwire 😉\n\u003c!-- ![TomServo32x32.png](TomServo32x32.png) --\u003e\n### Sophisticated Servo Management for the Discriminating User.\n\nThe TomServo library lets you power multiple servos\nfrom a single rechargeable battery. It works by putting the\nservo control pin into a high-z state when it is not \nmoving so you disable the driving of the servo\nand greatly reduce the current used by all the servos in \nyour project.\n\nBy multiplexing the movements of several servos\nso that only one is on at a time you can run up\nto 8 servos from a single battery. Or many more\nusing only a few batteries!\n\nIn addition to being useful for power consumption, the library \nallows you to greatly reduce servo jitter in low torque servo \napplications. By definition, if the servo(s) don't have a lock on\na valid PWM signal then they also aren't constantly trying to adjust\ntheir position because they think the servo is ever in the *\"wrong\"*\nposition.\n\n**Example Use:**\n```cpp\n/* \n * TomServoSweep.ino\n * \n * Example sweep using two servos.\n * Each servo is swept back and forth over the specified amount of time.\n */\n#include \u003cTomServo.h\u003e\n\nint const Servo1Pin = 5;\nint const Servo2Pin = 6;\n\nTomServo servo1(Servo1Pin);\nTomServo servo2(Servo2Pin);\n\n// The time to take to move to the destinations (in ms):\nint const duration1 = 2000; // 2 seconds\nint const duration2 = 4000; // 4 seconds\n\nint destination1 = 0;\nint destination2 = 0;\n\nvoid setup() {\n    servo1.begin(destination1);\n    servo2.begin(destination2);\n}\n\nvoid loop() {\n    servo1.update();\n    servo2.update();\n\n    // change directions when they reach their destinations:\n    if (servo1.complete()) {\n        if (destination1 == 0) {\n            destination1 = 180;\n        } else {\n            destination1 = 0;\n        }\n        servo1.write(destination1, duration1);\n    }\n\n    if (servo2.complete()) {\n        if (destination2 == 0) {\n            destination2 = 180;\n        } else {\n            destination2 = 0;\n        }\n        servo2.write(destination2, duration2);\n    }\n}\n```\n\n# Theory of Operation\n\nA servo motor only drives the higher voltage motor drive circuitry *after it has latched onto a valid PWM position*. This is required so it can compare the current position against the new position (received via the width of a PWM pulse) and make any necessary adjustments to the position of the main drive shaft by powering the motor and moving it forwards or backwards.\n\nMany people don't realize that the motor drive circuitry is **always** engaged and consuming current **even when the servo has reached its target position! As long as the servo is receiving a PWM pulse, it is comparing that position against the current drive shaft position and making tiny adjustments to the motor's position. This consumes a huge amount of power in projects that use servos.\n\nIf the servo is not receiving a valid PWM signal, then it does engage the motor drive circuitry. It's that simple. The driving of the motor is responsible for about ~3/4 of the total power consumption of servos so by stopping it we greatly reduce the idle power requirements of all of the servos in our project combined. \n\nWhen the `attach(pin)` method is called on a `Servo` object, then the internal `Timer1` registers are configured along with an interrupt to start generating a PWM signal on the specified pin. There is a companion method to `attach(...)` called `detach()`. When `detach()` is called on a `Servo` object, then the PWM generation is stopped. \n\nIn the future if the position of the servo needs to be changed by calling `write(...)`, then the `attach(...)` method must also be called again to restart the PWM generation. Once a new position has been written to the servo, it must be given a certain amount of time to physically move to the new position. \n\nThe TomServo library and class work by constantly iterating through all of the servos which have not yet reached their final target position. Each servo's position is incremented or decremented by 1, and the servo is given a short amount of time (~30ms) to physically move to the new position and then the `detach()` method is called in order to stop the PWM generation and lower the power consumption.\n\nThis iteration continues until all servos have been given time to reach their new target positions and they are all left in a detached state, consuming as little power as possible from a controlled servo.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fripred%2Ftomservo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fripred%2Ftomservo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fripred%2Ftomservo/lists"}