This is a work in progress. Will provide updates here and remove this banner when ready for others to use.
Earth date: Dec 26, 2024
The basic code will work to control the arm angles and select arm configs. Working on Ros2 integration.
The software and docs for my robotic arm.
- Physical build parts needed
- Onboard computer and micro controller
- Getting started
- How it all works
- Gallery
Note that I receive no compensation of any form from Amazon, it's just the one place where I know you can find all of these parts. Please do shop around. Temu and others have some of these parts for half as much.
quantity | part needed | cost | link |
---|---|---|---|
1 | 35Kgcm 270° servo for end effector | 28.96 | amazon |
1 | 20Kgcm 270° servo for iphone rotator | 14.99 | amazon |
2 | 60Kgcm 270° dual shaft servo for top arm segments | 30.00 | amazon |
1 | 150Kgcm 270° dual shaft servo for bottom arm joint | 44.00 | amazon |
1 | 60Kgcm 270° single shaft servo for base turntable | 34.89 | amazon |
36 | M2 16m cap head bolts (for 3 arm join servos) | 6.28 | amazon |
36 | M2 washers | 7.99 | amazon |
24 | M3 12mm self tapping screws | 5.49 | amazon |
4 | M5 20mm button head screws for mounting turn table servo | 8.99 | amazon |
4 | M5 nuts | 6.99 | amazon |
1 | 5x14x5mm bearing for iphone tilt arm effector. | 7.69 | amazon |
1 | 80x105x4mm thrust bearing for turntable base. | 8.78 | amazon |
3 - 4 ft | 3/4" Spiral wrap | 6.99 | amazon |
You will also need to make or buy extension cables for the upper servos. You can make your own if you have crimpimg tools and skill, wire, and a set of Dupont connectors something like this set. Or you can just buy premade servo extension cables.
I have tried be as platform agnostic as I can and the scripts and python code should work with any single board computer and servo controller supported by Adafruit's servo-kit
I know it works on a Raspberry Pi 4b (4GB), Raspian Bullseye 64, with the Adeept Motor Hat because I had extra laying around. The nice thing about the Adeept hat is that it has the power converter that can take any 12 - 60VDC power supply, supply the motors and also supply clean stable 5V power to the Raspberry Pi.
The fixed base model and sbc mounts were designed for the Pi 4/5 and may not fit larger sized SBCs, you will need to rectify that in Tinkercad on your own or house your SBC separately.
For build help, here is the link to a web mockup shared from my fusion 360 disigns that shows the build with servos in place: https://a360.co/3Phep9W
Connect the servos to the servo controller such that the base turntable servo is channel 0, and then up from there in sequential order.
git clone https://github.com/littlebee/strongarm.git
You will need to be able to SSH into the onboard computer to upload code. Ensure that you can successfully log-in,
ssh myrobotarm.local
replace "myrobotarm.local" with the hostname of your onboard computer or its IP address.
Setting up SSH on the SBC will be dependent on the SBC used and variatation of Linux. For Raspian on Raspberry Pi, here is a good article. The raspian image flasher will now alow you to setup SSH from the initial boot full security.
I work on a macbook and use iTerm2 for terminal. One of the additions I like to make to the standard setup, is to use the same user name on the Pi that I use locally on my mac. This allows not having to type ssh [email protected]
, because the name is the same just ssh mybot.local
works.
I also like to add my public key to the ~/.ssh/authorized_keys
file on the remote SBC. This will stop it from prompting you for the password on every SSH command (upload.sh uses rsync which uses ssh). I made a gist of the script I use to upload my public key to new boards.
./upload.sh myarm.local
Upload script uses rsync to upload which only updates changes and is incrementally very fast. You will use this script often and you intend to make changes to the code.
The upload script will default using your local $USER env. If you want to use a different user ID on the remote, you will need to specify both the host with user@ prefix and the directory to upload to:
./upload.sh [email protected] /home/pi/strongarm
If you forget to add the directory when using [email protected]
, you'll likely see a cryptic rsync error in the local terminal.
# ssh onto the machine and cd to the strongarm dirctory.
ssh myarm.local
cd ~/strongarm
./setup.sh
You will need to confirm any packages that need to be installed.
Optional: If you want the robot to start all of the services on boot, you can run these lines from the comments in ./setup.sh
script:
# rc.local calls start.sh
sudo cp setup/files/etc/rc.local /etc/
sudo chmod +x setup/files/etc/rc.local
# ssh onto the machine and cd to the strongarm dirctory.
ssh myarm.local
cd ~/strongarm
# run (on remote) startup script
./start.sh
That's pretty much it (if everything works, which it may not). The start script reads the paths of python scripts that start the needed services (see, services.cfg
). Each Python script is launched in the background, the PID is saved (for ./stop.sh), and it's error and std output is saved to ~/strongarm/logs.
ps -ef | grep python3
Compare to services.cfg
to ensure that all of the service python scripts are running. Note that just because a service has a running process does not mean it is not failing somewhere.
If the web_server.py and central_hub.py services are running, you might be able to get debug information from the web ui at http://myarm.local. Click on the "HUB STATE" in the upper left corner and scroll down to subsystemStatus
When started via ./start.sh
, each subsystem redirects its console ouput (stdout and stderr) to log files in ~/strongarm/logs
.
It is likely that the SBC operating system or Python installed onboard the bot may not have a either an OS package or a Python package that is required. These types of errors require [Inspecting the log files] to see the error that indicates which package(s) are missing at runtime.
If you find a missing package, please be a sport and add it to setup.sh
and submit a PR, or just open an issue and let us know if something is missing.
The backend components are written in Python and the web UI served from the bot's Raspberry PI is in Javascript and React.
The .stl files for the 3d parts I designed in Fusion 360 are used along with three.js to render the arm in the web UI. You can 3d print the parts from the .stl files directly from the .stl files in src/webapp_vite/putlic/arm-parts. For my build pictured, I used Bambu Labs PLA-CF filament, at 0.2mm line height with 50% rectilinier infill.
You can also add different arm configurations, say if you want another 80mm segment or a different effector, you can easily add your own arm config JSON file to the arm-configs folder
Central Hub src/central_hub.py is an ultra light weight websockets pub/sub service for the other components that provide (publish) and comsume (subscribe) state. The authorative state of the overall system (like what angles the servos are set) is owned and maintained by central_hub.
The other Python services (processes) use hub_state.py and also optionally messages.py hub_state_monitor.py to send and receive messages from central hub over a websocket cient connection and maintain their own local copies of the subscribed keys of the current state.
All data sent over the websocket to and from central_hub is in json and has the format:
{
"type": "string",
"data": { ... }
}
Where data
is optional and specific to the type of message. The following messages are supported by central-hub
:
example json:
{
"type": "getState"
"data": ["keyName", "keyName"]
}
Causes central-hub
to send the full state via message type = "state" to the requesting client socket.
data
is optional, if specified, should be array of key names to retrieve. If omitted, all keys (complete state) is sent.
example json:
{
"type": "identity",
"data": "My subsystem name"
}
Causes central-hub
to update subsystems_stats
key of the shared state and send an "iseeu" message back to client socket with the IP address that it sees the client.
example json:
{
"type": "subscribeState",
"data": ["system_stats", "set_angles"]
}
Causes central-hub
to add the client socket to the subscribers for each of the state keys provided. Client will start receiving "stateUpdate" messages when those keys are changed. The client may also send "data": "*"
which will subscribe it to all keys like the web UI does.
example json:
{
"type": "updateState",
"data": {
"set_angles": [127.4, 66.4, 90, 90, 0],
"velocity_factor": 1.5
}
}
This message causes central-hub
merge the receive state and the shared state and send stateUpdate
messages to any subscribers. Note that the message sent by clients (type: "updateState") is a different type than the message sent to clients (type: "stateUpdate").
As the example above shows, it is possible to update multiple state keys at once, but most subsystems only ever update one top level key.
The data received must be the full data for that key. central-hub
will replace that top level key with the data received.
For the latest message types and information about the their data structure, see messageTypes
supported in central_hub
Also look at https://github.com/littlebee/strongarm/blob/main/src/commons/hub_state.py which maintains this application's supported state, what state keys are persisted, how state is merged from messages. A few convienience methods for python clients can be found in src/commons/messages.py.
On the Javascript side, the webapp has similar components for hub state and hub messages