Comments (11)
Wow, thank you so much for taking the time to write this and also for investigating so thoroughly!
These are exactly the intended use cases, so I really appreciate seeing this being used well.
You've got everything exactly right, and I would pretty much say "yes-to-all" your suggestions.
In fact, some of the requested features are planned but didn't make the cut for the 2.0 release. Now I've got a good reason to bump them higher up the priority list for 2.1.
To make sure I answer this in detail, I'll probably go over your points one by one in the next couple of days (I'm on UTC+2). Feel free to nudge if I failed to respond to some of your comments in while.
But I'm going to respond to one point now because it is in fact on the list for next week, and maybe you're interested to help:
I haven't tested this yet, but I am wondering about how the acceleration curve will play with a higher level PID (or just P) controller calling drive(). For example, to follow a line (or go straight with a gyro)
And related to this, I'll also answer your question about settings
and limits
being the same or not. You hit the issue spot on: I realized it is kind of impossible to find one set of control
parameters that covers the use cases 1 and 2. For 1 we want precision (slow acceleration) and for 2 we want responsiveness (high acceleration).
And so that's why the separate settings
function was introduced. This will let us set low accelerations just for straight
and turn
(and one day, you guessed it, arc
), while setting much higher defaults for everything else.
The action point for next week is selecting those faster defaults, to ensure that indeed we are responsive enough to follow lines well by default. Right now, since I didn't get to this yet, the DriveBase heading and distance control adopt the settings dynamically from their respective motors, so it behaves just about the same as two single Motor
class objects would.
So I'm kind of expecting that we will have to adjust them to accelerate faster, because for single motors we set the default acceleration to be rather slow. All other settings are up for change as well. For example, we may need to reduce the aggressiveness of the PID controller as we increase the magnitude of acceleration.
I would like to ensure that by default, a simple loop like:
db.drive(drive_speed=some_user_constant, turn_rate=light_error*another_user_constant)
works well enough to make a decent proportional line follower, for small drive bases (42 mm wheels) and the educator bot (56 mm wheels, at the top of my head).
So if you have a robot on which you're willing to test this or even experiment with the control parameter values yourself, that would be really great.
If you are going to try other values, don't worry about reviewing the current defaults in great detail, as they are somewhat arbitrary so far. Feel free to focus on what works best for your robot. If you want to share those along with the robot's approximate dimensions, we'll have one extra data point to work with, which would be really great.
Thanks again. - I look forward to responding to your other points as well later.
from support.
Oh, please do try the latest beta release on April 10th. It has a few minor improvements like more verbose messages for error codes like EPERM
.
from support.
I'll switch over to the latest beta...are you keeping a log of release notes lying around somewhere?
At the moment, I'm testing with my older team's robot from last season. It uses the Lego "znap" wheels which are about 50mm diameter but excellent for this sort of thing as they have no air gap between the tread and rim...very precise. On their robot the center to center wheel base (axle_track) is 95mm. I'll try some line follows tomorrow AM and see how aggressive I can get the parameters before it is no longer reliable. Videos of this robot in action are on their YouTube channel
from support.
First off, let me say a big THANK YOU for doing this. This is exactly what I have been looking for for years. We start kids in FLL as early as 3rd grade and by the time they have been doing it for 3+ years, they often outgrow the MindStorms/LabView environment. Its not that the next lessons can't be taught there, its just not optimal. So having this level of control over things like acceleration (both straight and angular!) is really great. The kids will be able to dip their toes in the water of actual physics computations and, for their efforts, have a much improved level of control over their robot's odometry.
Let me start by saying I'm really happy to hear this perspective from an experienced teacher and FLL coach.
I say that because we have also heard the opposite, where some insist that we should not provide this. They argue that it takes away the learning.
I would argue that useful and transparent tools encourage learning. Indeed there's the physics principles you mention. But on an even more basic level, I'd argue it encourages kids to get a ruler and start measuring, as opposed to endlessly trying to guess the "right" the numbers for the conceptually opaque green blocks.
And also, I would argue that not every FLL or STEM student needs to be or become an engineer. There's a lot to learn about application design, problem solving, mission planning, team work and beyond, but it can be a very discouraging hurdle if everyone must learn about wheel geometry just to get there.
from support.
I agree with your perspective here. Here are a few additions:
FIRST is a big place, with many diverse opinions. Many of those opinions come from engineers who have made a career at a particular level of the "universal engineering stack", ranging from physics and material sciences, up through ME, into Comp Sci, and then up into project/program management. The wonderful news is that FIRST has room for all of them and the lessons their careers have embodied. The mixed blessing is that people tend to overvalue that which they know. So the Physicists will argue that the kids should learn about momentum and torque and shy away from platforms that hide those details. The MEs will argue that kids should learn about simple machines and be displeased when Lego introduces new parts that fully encapsulate linear actuators. The OS people might bristle at the conversation on the other thread here about hiding vagaries of device drivers, the Apps people will argue that the kids should work out PID control on their own, and so on.
Experienced coaches know that there is a universe of practical learning to be done in FIRST and they tailor the experience to each team, each season. For one team, they may hand them a platform component that neatly encapsulates a tough problem, for another team, they neglect to mention that component exists and coach the kids through recreating it.
They also know that FIRST is foremost, an educational enterprise, and the competitive aspect (like the robots) is just the "hook" to keep the kids interested and engaged. Platforms always gain capability over time, both in the "real world" and in contrived worlds like FIRST competitions. Its called progress. Its also essential to keeping FIRST relevant in a rapidly evolving world. This last season, 50% of more of FTC teams used real time computer vision with AI based object recognition. Virtually none of them understand how that works, they just use the code the platform provides. But, they did learn many of the problems associated with adapting and utilizing those technologies and, importantly, the FIRST ecosystem is keeping up with the state of the art.
FLL made a bold and committing move last season to open up the competition to other coding platforms. That move will change the competition forever. With the introduction of text based programming languages, source code control will take root in FLL, which will drive many teams to github, which will open the door to code sharing. Very strong teams will see the "core values" opportunity to create and share code libraries for other teams to use. This has been standard in FTC and FRC for years, now it will come to FLL.
So your work is not only healthy and of great merit, it is inevitable. If you (with Lego Education and FLL) don't provide it, teams will. And in fact, whatever level of platform you do provide, that will be extended further by teams, "platformized" and shared broadly.
I think it is wonderful that this work is being done and even more wonderful that it is sanctioned and promoted by Lego Education and FLL. Please keep up the good work!
from support.
Thanks for your follow-up there as well. We're certainly looking forward to seeing students use this in FLL. As you've found, many of the Motor
and DriveBase
functionality is designed to improve accuracy and simplicity for core robot tasks, used in FLL and beyond.
In the next couple of posts, I'll try and go through some of your specific comments and questions.
from support.
---I LOVE how the robot can be "configured" with its wheel_diameter and axle_track. This is a great opportunity to teach some basic geometry to the kids and then let them move on to higher order problems.
And there's room for further experimentation too. In practice, for example, rubber tires compress a bit, leading to a smaller "effective" diameter. And the motor shaft and axle are slightly flexible, usually leading to a smaller "effective" axle track than just the midpoint of the wheels.
------I typically talk to the kids about straight movement, turns (radius turns) and spins (spinning in place). As I understand it, radius turns are missing in this part of the API. Perhaps those could be added?
This is something we might add later (2.1 or later).
I wonder if the straight_speed and turn_rate parameters could be included as inputs on the movement methods themselves (e.g. straight(distance, speed))
Yeah, this is the pattern we use for Motor
.
We've decided to make straight
and turn
really basic on purpose, making the DriveBase
a good entry point for learning programming in general too (not necessarily robotics).
Done this way, there's a lot less ambiguity regarding double negatives. For example, doing straight(-100)
intuitively makes the DriveBase go backward.
Even if we won't encourage it, in practice some programs might end up looking like this, comparable to many green blocks in sequence:
robot.turn(90)
robot.straight(200)
robot.turn(-90)
robot.straight(100)
This is much easier to read and debug compared to:
robot.turn(90, -90)
robot.straight(200, 100)
robot.turn(-90, 1000)
robot.straight(100, -200)
from support.
It wasn't initially apparent to me that subsequent calls to drive() would "automatically" enact the specified acceleration curve to handle differences in velocity, but once that came clear, I do like it. Perhaps some notes in the doc.
There's no difference between the first or subsequent calls. It just accelerates to and stays at the requested speed in run(speed)
. Likewise, it accelerates and stays at the requested drive speed and turn rate in drive(drive_speed, turn_rate)
.
As a curiosity, what did you initially expect before seeing this result? Faster acceleration?
I haven't tested this yet, but I am wondering about how the acceleration curve will play with a higher level PID (or just P) controller calling drive(). For example, to follow a line
Indeed, we've started to zoom in on this in #18 .
Provide an explicit way to disable the acceleration curves. Perhaps this is just setting the acceleration numbers to arbitrarily large values?
Indeed, picking a higher value is what you could do. A mechanical system is always going to have to accelerate. To get a sense of how fast that is, perhaps set dc(100)
and see how fast your motor accelerates. As a helping hand to see what is arbitrarily large, consider trying to reaching the maximum speed in one control step (0.01 seconds).
I'm not sure how to stop. I haven't tried calling straight() after a call to drive(speed,0). Perhaps that is the plan?
Before getting into details, it is quite intriguing why people seem to assume that "0" is different and should not be used (This is quite a common assumption, but I'm not sure why.)
My workaround is to call drive() with a very slow speed, let it decelerate for a specific set of encoder clicks, and then call stop() and brake().
So in this case, why a very slow speed, and not just drive(0, 0)
? Like any other drive
command, it accelerates/decelerates smoothly to the target speed, so 0 in this case.
One thing we considered but did not add yet, is a decelerate()
method, which would essentially just call drive(0, 0)
and then conveniently wait until the speed reaches 0 like you described. Would you find this useful?
Or, maybe instead an optional argument wait
(True
/False
) on drive
could capture both this, as well as blending multiple drive
commands the way I think you wanted.
But yes, straight(0)
and turn(0)
would be an abrupt stop, and stop()
just coasts the motor.
I'm not sure how far you want to go with this, but it occurs to me that you could potentially expand the straight() and turn() API to enable "optional" stops.
Indeed, an optional end_speed
could be a next step. The good news is that the controller concept and implementation would allow for this. But it would still be a pretty major change. We're hoping that the existing turn
and straight
will still be quite useful for FLL teams.
Combined with the posts elsewhere, I think this covers most of your questions or comments.
Thanks again for your detailed testing and sharing your insights.
from support.
Thanks for being so responsive and tolerating all this "input"!!
less ambiguity regarding double negative
Excellent point! This is a perennial thorn in my side teaching kids...and I take your point about teaching basic programming. And it will be a fine exercise for teams to extend this API to forward(), backward(), etc.
As I understand it, radius turns are missing in this part of the API. Perhaps those could be added?
This is something we might add later (2.1 or later)
Yes please! Before next season if possible?
There's no difference between the first or subsequent calls. It just accelerates to and stays at the requested speed in run(speed). Likewise, it accelerates and stays at the requested drive speed and turn rate in drive(drive_speed, turn_rate).
As a curiosity, what did you initially expect before seeing this result? Faster acceleration?
My particular thought process: When I first looked at drive() it was right after trying straight() and turn() which seem to assume that the robot will be at rest before and after the movement. So I was looking for the "missing" arc() and thinking about that sort of thing. I wrote code that used drive() along with distance() and angle() to try that out. That was when it occurred to me that It wasn't clear how to stop with a deceleration curve. Not sure why drive(0,0) did not occur to me, but it does "read" as a bit of a contradiction until you grok that "drive" means "accelerate/decelerate to the commanded speed and hold it" (as you say, people are indeed intriguing...). There were also a couple of words in the doc that probably threw me off:
Drive Forever
Use drive() to begin driving at a desired speed and steering.
It keeps going until you use stop() or change course by using drive() again.
A few well chosen words and something about changing velocity on the fly (as well as heading) might go a long way here.
why people seem to assume that "0" is different and should not be used
In my experience, when people don't see something like that, it is often the name of the method. I'm not suggesting you change anything here, but for illustration, consider the difference in understanding created by "drive()" versus something like "change_velocity_to()" or even "accelerate_to()"
One thing we considered but did not add yet, is a decelerate() method,. Would you find this useful?
Or, maybe instead an optional argument wait (True/False) on drive could capture both this, as well as blending multiple drive commands the way I think you wanted.
Indeed, an optional end_speed could be a next step
We're hoping that the existing turn and straight will still be quite useful for FLL teams.
I have the impression that you have a design goal to provide an API that can be approached at multiple levels of understanding. For example, doing some simple configuration (or accepting defaults) and then using a sequence of calls like straight(500) and turn(90) is a wonderfully simple way of starting. For kids new to programming, learning Python and robots all at the same time, this level of simplicity is just what you need. At the other end, you also seem to be targeting a level of configuration and control here that is rarely seen at much higher levels of youth robotics (integral_range? Bravo!). Designing an API that is useful from one end of that scale to the other is no easy task!
As far as specific recommendations go, I'll offer these:
- Be careful about adding complexity to the simple stuff, even default parameters create more that one has to think about. So probably disregard my earlier suggestions about adding parameters to the basic movement methods.
- Clean delineations in the API can be useful to help people know which "level" they are working with. You seem to be doing that in the doc, but maybe there is room to do that in the API itself through naming conventions.
- Going back to the 3 use cases outlined at the top of this thread, with the addition of "arc()", I think basic movement is covered.
- For Sensor Controlled Movement that goes until a discrete event occurs (the classic MindStorms MoveSteering / Wait block combination), I think drive() is fine (with some tweaks to the doc I mentioned above), but I would suggest adding a hold() method that can be called when the event is triggered in addition to the stop() method (or perhaps a parameter of type "Stop"). A robot trundling up to a line and stopping is a classic educational design pattern. They can learn about controlling momentum later. For movement controlled proportionally to sensor readings, drive() also seems to fit the bill, and there is plenty of depth there for the most devoted.
- For use case 3, where you want a series of odometry based movements that blend into each other (without stopping between), that is where the API doesn't seem to offer much. It can be done with drive(), distance() and angle() as is, but perhaps some additional parameters could make it easier. Adding in notions of distance and end_speed, and perhaps breaking up the different sorts of movements (like you have with the basic movements) might be one way to go. For example:
drive_straight(distance, cruise_speed, end_speed=None)
drive_arc(radius, degrees, cruise_speed, end_speed=None)
drive_turn(degrees, cruise_speed, end_speed=None)
end_speed = None indicates no change of velocity at the end, just returns control.
end_speed = 0 means decelerate to 0
from support.
Thanks for sharing your thought process on some of your points.
Yes, we aim to make it simple for beginners and useful for advanced users at the same time. I think this can work well if the core principles work well and reliably.
Then, by picking sensible defaults but keeping options meaningful and configurable, advanced users will be able to extend it in many ways. Essentially we aim to make it simple, but not simplistic.
Now that most implementation is done, we'll turn our attention to continuing filling the gaps in the docs as you correctly point out. And eventually, hopefully we'll add some more samples to illustrate the various use cases like discussed in this thread, and how they can be useful for teams.
from support.
The following features are now available 🎉 🤖
- Driving along a curve of a given radius.
- Continuing two commands without stopping between each call.
- Separate acceleration / deceleration settings
This seems to cover most of the feature requests here, so I think we can close this issue.
Please do not hesitate to share your findings if you try any of these features :)
from support.
Related Issues (20)
- [Bug] HOT 1
- [Bug] Can't shut down during stuck task that is not cancellable HOT 16
- [Feature] Python code snippet within blocks HOT 1
- Support Collapsing / Folding of Tasks in Block Programs HOT 1
- [Bug] xbox controller disconnect with pybricks HOT 8
- [Bug] Uncatched error on code.pybricks.com on loading a block-code program with an unsupported block HOT 5
- Block to Python Generator Multiplies Arguments in `multitask until` HOT 3
- [Bug] Some Blockly UIs overlap Pybricks Code UIs
- [Feature] Support submodules HOT 8
- [Feature] Improve BLE requirements note on Windows 7 platforms
- [Feature] Is there any function like "thread" (not multitask) implement in pybricks with SPIKE Prime? HOT 7
- [Feature] Is there any function can directly contorl the PWM of each port? HOT 7
- [Feature] Toggle Bluetooth with Bluetooth button. HOT 29
- [Feature] Also reset heading target when resetting odometry. HOT 5
- [Feature] Reserve memory region for persistent system settings. HOT 10
- [Feature] Relax speed cap for external Boost motor HOT 3
- [Bug] Local loop variable nested in multitask not generated correctly HOT 4
- [Feature] Support changing editor zoom level on Android
- [Feature] Improve importing functions shared between block programs HOT 4
- [Bug] Fix changelog location HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from support.