I'm a frontend web engineer - building performant, high-quality user interfaces. Formerly, a robotics teacher.
Above stats generated with: tipsy/profile-summary-for-github
A hexapod robot simulator built from first principles
License: MIT License
I'm a frontend web engineer - building performant, high-quality user interfaces. Formerly, a robotics teacher.
Above stats generated with: tipsy/profile-summary-for-github
hexapod.Linkage
Format this better
hexapod-robot-simulator/hexapod/linkage.py
Line 158 in 35cac5c
Use a for loop instead
hexapod-robot-simulator/hexapod/linkage.py
Line 142 in 35cac5c
The variable trio isn't being used at all, should we even return it, or should we just return the n axis and the height?
While porting this to javascript I have discovered so many ways to improve the code structure and algorithms found in this project
Take a look at the following files on the new project
https://github.com/mithi/hexapod/blob/master/src/hexapod/Linkage.js
https://github.com/mithi/hexapod/blob/master/src/hexapod/VirtualHexapod.js
https://github.com/mithi/hexapod/blob/master/src/hexapod/basicObjects.js
def _draw_hexapod(self, fig, hexapod)
def _draw_scene(self, fig, hexapod)
def change_camera_view(self, fig, camera)
Live on https://hexapod-robot-simulator.herokuapp.com
Convert this to to be a fully client-side JavaScript app?
hexapod.models
hexapod.linkage
hexapod.ik_solver.ik_solver
hexapod.ground_contact_solver
https://github.com/mithi/hexapod-robot-simulator/blob/master/hexapod/models.py
https://github.com/mithi/hexapod-robot-simulator/blob/master/hexapod/linkage.py
https://github.com/mithi/hexapod-robot-simulator/blob/master/hexapod/ground_contact_solver.py
https://github.com/mithi/hexapod-robot-simulator/blob/master/hexapod/ik_solver/ik_solver.py
Should be poses.key()
not poses.items()
hexapod-robot-simulator/pages/helpers.py
Line 22 in 5d0d7be
Currently the legs on ground is tilted with respect to the hexagon which is in the xy plane
the polygon defined by the legs on ground must be parallel to the xy plane,
it's the polygon which must be tilted
You'd need to update the following
1. The model VirtualHexapod
to have an attribute that stores this point
hexapod-robot-simulator/hexapod/models.py
Line 95 in 531fbb3
You can compute this point as outlined by the algorithm here, you should inject the point calculation to a different function and update the attribute of the VirtualHexapod
when this is called in the two compute_orientation_properties
of the hexapod.ground_contact_solver
module.
2. In figure template, you should append a new point trace at the end of the data
list
The trace has the following format
{
"marker": {"color": INSERT_COLOR_HERE, "opacity": 1.0, "size": INSERT_SIZE_HERE},
"mode": "markers",
"name": "cog-projection",
"type": "scatter3d",
"x": [INSERT_COG_X_HERE],
"y": [INSERT_COG_Y_HERE,
"z": [0],
}
3. HexapodPlotter
could draw this point in the figure template
If all feet are on the ground,
and only one of the legs (coxia) pivot, how should the hexapod react?
SHOW_DETACHED_HEXAPOD = False
hexapod-robot-simulator/hexapod/linkage.py
Line 161 in f67434e
IE do this instead
ground_contact = self.p3
for point in reversed(self.all_points):
if point.z < ground_contact.z:
ground_contact = point
We display the current state in the user interface even though the widgets are already displaying it. Is that really necessary?
See:
For each page we have a sort of block like this
GRAPH_NAME = "graph-kinematics"
ID_MESSAGE_SECTION = "message-kinematics"
ID_PARAMETERS_SECTION = "parameters-kinematics"
sidebar = shared.make_standard_sidebar(
ID_MESSAGE_SECTION, ID_PARAMETERS_SECTION, SECTION_POSE_CONTROL
)
layout = shared.make_standard_page_layout(GRAPH_NAME, sidebar)
outputs, inputs, states = shared.make_standard_page_inputs_outputs_states(
GRAPH_NAME, ID_PARAMETERS_SECTION, ID_MESSAGE_SECTION
)
I'm not a fan of the variable names
maybe something like
graph_id
parameters_section_id
message_section_id
respectively is more meaningful and appropriate
Should it? The IK solver checks it, and the widget slider constraints the angles as well.
Replace:
hexapod-robot-simulator/index.py
Line 14 in 808534d
With:
div_header = html.Div(
[
html.A(html.H6("👾"), href=URL_REPO, target="_blank", style=icon_link_style),
html.A(html.H6("☕"), href=URL_KOFI, target="_blank", style=icon_link_style),
dcc.Link(html.H6("●"), href="/", style=icon_link_style),
dcc.Link(html.H6("●"), href="/inverse-kinematics", style=icon_link_style),
dcc.Link(html.H6("●"), href="/kinematics", style=icon_link_style),
],
style={"display": "flex", "flex-direction": "row"}
)
So that the page does not not refresh
All other legs work fine.
Reimplement inverse kinematics solver (hexapod.ik_solver2
). The current implementation hexapod.ik_solver
involves a bunch of tiny helper methods and one big god function that tries to do almost everything. I plan to redesign this by making a class that centers around this responsibility.
How to determine how the hexagon body will twist around its z axis?
Ideas:
given pose before and pose after
determine which leg points are on the ground
on both before and after.
This points are the "pivot" points.
which means the shape of the polygon defined by these points
should be the same in the pose before and the pose after.
get any point in this set.
the angle between the vector A and B
where A is the vector from center of gravity to point in old pose
and B is the vector from center of gravity to point in new pose.
is the angle of the twist???
Remove type
parameter for def make_translate_slider
It is not used and it doesn't make any sense.
hexapod-robot-simulator/widgets/ik_ui.py
Line 34 in 5c1f8a1
Use None instead of {} as default parameter as per convention
It seems like we don't actually need to store n_axis as an attribute
hexapod-robot-simulator/hexapod/models.py
Line 108 in 5c1f8a1
The body should be positions wrt to the feet
right now the feet is positioned wrt to the body
So it's easier to see how the robot is tilted
If the height of the foot tip is greater than the point of contact with the body,
use the point of contact with the body instead.
You shouldn't be able to do that,
Check adjacent legs if they're going to crash to each other.
Prevent this by just rotating at the best acceptable range (increment by 5 degrees maybe?)
# ❗❗IMPORTANT!This assumes leg with id 3 and id 4 are on the ground
# THIS IS NOT ALWAYS THE CASE.
# Should check which two legs are both on the ground before and after
# instead of using leg 3 and 4
When Hexapod.ground_contact_solver.legs_
can't find a stable pose, Hexapod.models.VirtualHexapod
will render hexapod with cog at Point(0, 0, 0)
The old algorithm rests upon the assumption that it knows which point of the each leg is in contact with the ground. This assumption seems to be true for all possible cases for
leg-patterns page and inverse-kinematics page.
But this is not true for all possible angle combinations (18 angles) that can be defined in
the kinematics page.
This current algorithm will still be used for the leg-patterns page, and the inverse-kinematics page. A more general algorithm will be used for the kinematics page
The following algorithm can be used for the leg-patterns page and inverse-kinematics page.
(How to find the ground contact points, tilt, and height of the hexapod)
But this can't be used in general.
This is because how we determine the ground contact ie Linkage.compute_ground_contact()
doesn't always yield the correct result.
hexapod-robot-simulator/hexapod/linkage.py
Line 162 in 45acb5a
Here's the new algorithm that accounts for most cases
The way it works right now is,
for each update, a new hexapod is created from scratch (all angles = 0)
and then the hexapod poses is built from there on.
It would be better if we remember the old hexapod pose, especially for computing twists along the z axis.
We are using the Point class for 3d Vectors as well. I think the Point name is loaded, Vector is a more generalized term for a set of three numbers
This implementation uses matrices, not quaternions. I'm aware that quaternions is far superior in every single way.
It might also be interesting to benchmark the performances of the two.
Good reference(s):
We currently have three pages apart from the landing page
All of them have the following:
GRAPH_NAME = "graph-hexapod-patterns"
ID_MESSAGE_DISPLAY_SECTION = "display-message-patterns"
SECTION_MESSAGE_DISPLAY = html.Div(id=ID_MESSAGE_DISPLAY_SECTION)
ID_POSES_SECTION = "hexapod-poses-values-patterns"
SECTION_HIDDEN_JOINT_POSES = html.Div(id=ID_POSES_SECTION, style={"display": "none"})
SECTION_CONTROLS = [
SECTION_DIMENSION_CONTROL,
*insert_widget_section_here*,
SECTION_MESSAGE_DISPLAY,
SECTION_HIDDEN_BODY_DIMENSIONS,
*insert_hidden_parameters_here*,
]
They also have something like this
OUTPUT_MESSAGE_DISPLAY = Output(ID_MESSAGE_DISPLAY_SECTION, "children")
INPUT_POSES_JSON = Input(*insert parameter section_id_here*, "children")
OUTPUTS = [Output(GRAPH_NAME, "figure"), OUTPUT_MESSAGE_DISPLAY]
INPUTS = [INPUT_DIMENSIONS_JSON, INPUT_POSES_JSON]
STATES = [State(GRAPH_NAME, "relayoutData"), State(GRAPH_NAME, "figure")]
We can refactor this into the shared module
Currently this is how we do it:
@app.callback(OUTPUTS, INPUTS, STATES)
def update_inverse_page(dimensions_json, ik_parameters_json, relayout_data, figure):
if figure is None:
return BASE_FIGURE, ""
dimensions = helpers.load_dimensions(dimensions_json)
hexapod = VirtualHexapod(dimensions)
ik_parameters = json.loads(ik_parameters_json)
hexapod, poses, alert = inverse_kinematics_update(hexapod, ik_parameters)
if RECOMPUTE_HEXAPOD and poses:
hexapod = recompute_hexapod(dimensions, ik_parameters, poses)
BASE_PLOTTER.update(figure, hexapod)
helpers.change_camera_view(figure, relayout_data)
if poses:
text = helpers.make_poses_message(poses)
else:
text = helpers.make_alert_message(alert)
return figure, text
We can do something like this
@app.callback(OUTPUTS, INPUTS, STATES)
def update_inverse_page(dimensions_json, ik_parameters_json, relayout_data, figure):
if figure is None:
return BASE_FIGURE, ""
ik_parameters = json.loads(ik_parameters_json)
dimensions = helpers.load_dimensions(dimensions_json)
hexapod = VirtualHexapod(dimensions)
try:
hexapod, poses = inverse_kinematics_update(hexapod, ik_parameters)
except Exception as e:
return figure, helpers.make_alert_message(e)
if RECOMPUTE_HEXAPOD :
hexapod = recompute_hexapod(dimensions, ik_parameters, poses)
BASE_PLOTTER.update(figure, hexapod)
helpers.change_camera_view(figure, relayout_data)
return figure, helpers.make_poses_message(poses)
This is bug when RECOMPUTE_HEXAPOD = True
in settings.py
The issue can be replicated by moving
percent.z
slider or percent.y
slider
Based on experience,
it is better if you can write the value you want directly
rather than finding where exactly in the slider is that value.
hexapod/
widgets/
pages/
tests/
hexapod/ik_solver/ik_solver2.py
- init
hexapod/linkage.py
- init
- str
- repr
hexapod/points.py
- init
- repr
- str
- eq
hexapod/models.py
- for VirtualHexapod
- for Hexagon
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.