jamesaguilar
Eurobricks Vassals-
Posts
10 -
Joined
-
Last visited
About jamesaguilar

Spam Prevention
-
What is favorite LEGO theme? (we need this info to prevent spam)
mindstorms/spike prime
-
Which LEGO set did you recently purchase or build?
EV3, I made a custom creation
Profile Information
-
Gender
Male
-
Interests
Lego, weightlifting, rucking, rowing, photography
Extra
-
Country
United States
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
Thank you for looking over it! This code actually does not do the same thing, because the result of motor.run_until_stalled() is not the same as motor.angle() after motor.run_until_stalled(). `run_until_stalled` returns the angle at which the stall is estimated to have begun, whereas angle returns the current angle of the motor. Given the torque of the motor w.r.t. to the rigidity of the structure, this means that the difference between the two angles could be as much as five degrees, with angle() being an overshot measurement. So you need to adjust for that when you reset the angles. Ah yeah. I am a programmer at my day job so I'm very used to the coding part. It's the lego building part that I'm inexperienced in!
-
Okay, I managed to get something working that I'm reasonably happy with. It took a lot of tweaking, the ole python is pretty rusty. But, it behaves in a distinctly robot-arm like way at this point: https://photos.app.goo.gl/9gYNdfNemzQ8pQnd7 What is happening here: Server program runs on EV3. It uses three bluetooth mailboxes: one to broadcast the (logical) range of its actuators, one to broadcast the actuators' current settings, and one to receive commands to move to a particular set of target angles in a particular number of milliseconds. Client program running on PC: Inverse kinematics computed using scipy Control algorithm creates a virtual point (starting at the initial real point of the arm). This point can move at most 5 lego units per second. Commands received via game controller update the virtual point. We ask scipy to solve the motor positions that will get us closest to the virtual point, using the current motor position as an initial guess. We always send the new motor positions to the robot. If scipy finds us a solution that is within one unit of bang on, we also update the virtual point with the new virtual point on each update. IK code is surprisingly easy (if you stand on the shoulders of giants): _r1 = 2.0 _l2 = 20.0 _l3 = 15.0 Vec3 = npt.NDArray[np.number[Any]] def get_radius(input: Vec3) -> float: return _r1 + _l2 * sin(input[1]) + _l3 * sin(input[1] + input[2]) def get_pos(input: Vec3) -> Vec3: """Finds the X,Y,Z vector given the settings of each motor. The settings of the motors are given in radians from their neutral positions.""" ar = input[0] a2 = input[1] a3 = input[2] r = get_radius(input) x = r * cos(ar) y = _l2 * cos(a2) + _l3 * cos(a2 + a3) z = r * sin(ar) ret = np.array((x, y, z)) return ret def get_err(input:Vec3, target: Vec3) -> np.floating: return norm(target - get_pos(input)) def get_motor_settings(target: Vec3, initial_guess: npt.ArrayLike): # I tried to differentiate this and I got a headache. Finite estimation methods ftw. initial_guess = initial_guess if initial_guess is not None else (0, 0, 0) return minimize(get_err, initial_guess, args=(target,), method="slsqp", jac="3-point", bounds=((radians(-90), radians(90)), (radians(17), radians(90)), (radians(-6), radians(161)))) Yep, that's really it. The whole repository can be found here. There are a bunch of other things you could do. For example, recording points and moving to them, or making the calibration a little more effective. Or if you wanted to this could serve as a basis for a more complete robot arm. One of the biggest things I learned from this project is that One Does Not Simply Build Technic. I thought, "how hard could it be?" And boy was I wrong. I had a lot of trouble accomplishing the shape of arm I desired compared to my expectations. I do not have any intuition for how to create joints properly or how to build up rigid shapes. If you take a look at the model, you'll notice that the bottom half is actually one of the starter projects for the EV3 set, not a design of my own. The arm is still mine, but I could not figure out how to get the base set up properly without some guidance. I think for my next few projects, I'm going to work through all the Mindstorms starter projects, and maybe buy a few used Technic sets to start getting a sense of the building techniques and also gathering a piece repository. After I've done that, I'll start thinking about what I want to create next.
-
World Record (maybe?)
jamesaguilar replied to kraai's topic in LEGO Technic, Mindstorms, Model Team and Scale Modeling
We're gonna need a lot of wheels where we're going. -
Right now I'm struggling through stuff that probably seems very basic to you more experienced lego builders out there. For example, sensing the limits of rotation on each of the arms. I do not have enough mindstorms buttons to make proper limit switches like you would in a real robot arm, so my strategy up to now has been to drive the motor at the lowest possible torque until it hits a physical limit that I've installed for each extreme of each axis. The problem is that the lowest amount of torque seems to still be quite a lot of torque. I'm nervous of damaging my pieces! I'm using this code to sense the limits. Please make any suggestions for how to improve things: def calibrate_throw(motor: Motor, speed: float, torque_fraction: int = 40): motor.stop() before_limits = motor.motor.control.limits() motor.motor.control.limits(before_limits[0], before_limits[1], torque_fraction) target_ms_per_degree = abs(1000.0 / speed) stalled_ms_per_degree = target_ms_per_degree * 2 quit_ms_per_degree = max(100, target_ms_per_degree * 3) avg_ms_per_degree = EWMA(target_ms_per_degree, 0.2) motor.run(speed) wait(100) angle_before = motor.angle() watch = StopWatch() watch.resume() while True: wait(50) angle_after = motor.angle() if angle_after != angle_before: diff = 1.0 * abs(angle_after - angle_before) ms_per_angle = watch.time() / diff for x in range(int(diff)): avg_ms_per_degree.record(ms_per_angle) watch.reset() print(watch.time()) if watch.time() > quit_ms_per_degree: print('had to quit took too long to get degree: ', watch.time(), ' > ', quit_ms_per_degree) break if avg_ms_per_degree.avg() > stalled_ms_per_degree: print('had to quit average fell too low: ', avg_ms_per_degree.avg(), ' > ', stalled_ms_per_degree) break angle_before = angle_after motor.stop() motor.motor.control.limits(*before_limits)
-
I see where the miscommunication was! :) What you have here is the closed/analytic solution to inverse kinematics of your arm. That means that given a particular position, you directly calculate the desired positions of each actuator. What I want to do is use an optimization algorithm to do the same thing. With SQP and other optimization algorithms, you don't explicitly calculate the inverse kinematics. Instead, you just provide: A function that computes your distance from the goal in goal-space given the inputs. (This is just absolute difference between the goal position & attitude and the forward kinematics.) The gradient function for the distance function. (I.e., the partial derivative of the distance function w.r.t. each input variable.) A list of constraints (i.e. "this motor can't rotate beyond position y"). These constraints can be linear or nonlinear. The gradient function for each constraint, again w.r.t. each of the input variables. The algorithm tries to find the global minimum of the distance function, which is to say it tries to find the setting of the motors that minimizes the distance from your desired position to the goal. But it can also incorporate things like obstacle avoidance via the constraint functions. You can look at scipy.optimize.minimize to see the function I intend to use.
-
When you say, "made your own program," I am understanding you to mean you made a python module that does all this by hand? SQP requires being able to solve systems of equations as well. You did that? And it runs fast enough to do an update every 50ms!? Very impressive. I did not think the EV3 was powerful enough. I may have another look at it, although it is possible that I'm not interested enough in the math to actually do that part on the device when a library is at hand on my desktop to do it all for me. ;)
-
Awesome! So, one wrinkle here is that I'm trying to do everything in pybricks-micropython. To my understanding there are no other real programming environments available on more recent bricks like spike prime. Unfortunately, it seems like pybricks cannot load c modules, so no numpy and no fast cpu intensive operations. The other wrinkle is that I'd really like to use an numerical/iterative solution even though it's plainly unnecessary for three axis. If only because I want to experience what a 7dof robot maker would in terms of software implementation. Since the project is just a one-off throwaway, I'll probably stick with the server based approach. But it's amazing to see what is possible with ev3! If I decide to stick with mostly ev3 rather than primarily using the spike prime set I have on order then I will have to investigate the c libraries to see what they can do.
-
jamesaguilar started following [WIP] Baby's first mindstorms project - 3-axis robot arm
-
I always lusted after mindstorms as a kid, but I never had it. I don't know why, because my parents got me various things. Maybe I just didn't ask? Anyway, now I'm an adult who has his own money, so I can have things like this. It's so exciting! I have scarcely built anything made out of Legos in twenty years, and it's truly a rush to be back. What I've built so far: a 3 axis robot arm with a 360 degree rotating base. I only have the ev3 set, so I don't have enough pieces to make anything really robust. Particularly, the arm is far too flimsy to hold a manipulator. At the moment I have a program to learn the throw of the upper two motors. The turntable can rotate 360 degrees, and I think I probably won't bother to write a zero function for it. I have worked out the math for the forward kinematics, at least in abstract. I have to measure the model to see where we actually are. I had initially intended to implement the forward kinematics locally. But then I tried to learn the SQP algorithm and my brain melted. I do not know if the EV3 would be powerful enough to run it. My new plan is to implement a very simple control server on the ev3 that will tell its position and receive commands to move. My desktop will run the inverse kinematics using the prebuilt SQP implementation in scipy. My next intention is to get one of the prior-year FLL kits and build a robot that can complete the tasks. I'm too old by far to play in these leagues now, but solving the challenges will be a fun project in its own regard. By the way, building this was really freaking hard, and I'm pretty sure there are a lot of illegal constructions in it! I was already impressed with the people who were skilled at modeling things in Lego, but now that I've tried building something myself, my level of amazement has at least doubled!