Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any way to pair motors? #13

Open
karlmdavis opened this issue Feb 3, 2021 · 3 comments
Open

Any way to pair motors? #13

karlmdavis opened this issue Feb 3, 2021 · 3 comments

Comments

@karlmdavis
Copy link

Apologies if this is a dumb question, but as someone new to Mindstorms and this library, I suspect there ought to be a way to pair motors together? Like, if I want to start driving, shouldn't there be a way to start both motors/wheels at the same time?

I see that the Python libraries have a MotorSet. Is that what I'm thinking it is and is there an equivalent for this library?

@pixix4
Copy link
Owner

pixix4 commented Feb 3, 2021

No, there is currently no such functionality. This library is based on version 1 of the python library wich does not have such utility functions.

As it seems, MotorSet is primarily used to set a command or get the current state for all assigned motor. But it is not possible to set the speed or the duty_cycle for each connected motor. So you either have to use a subclass like MoveTank which is limited to two motors or keep track of the motors manually to set the individual speeds. It is currently not planed to add higher level functions such as pid controllers, odometry or other such functionality provided by MoveTank and comparable classes.

But it would be possible to implement a slightly more advanced version of MotorSet that supports setters for individual speeds of motors. Such an implementation dependents on a subset of RFC-2000 (to check the parameter count for a set_speed function at compile time) wich is scheduled to for release in stable at 2021-03-25. Here is a proposed usage example:

let motor1 = LargeMotor::get(MotorPort::OutA)?;
let motor2 = LargeMotor::get(MotorPort::OutB)?;
let motor3 = MediumMotor::get(MotorPort::OutC)?;

let motor_set = MotorSet::create<3>([motor1, motor2, motor3]);
motor_set.run_direct()?;
motor_set.set_duty_cycle_sp([50, 70, 30])?;
motor_set.stop()?;

This would achieve the same as:

let motor1 = LargeMotor::get(MotorPort::OutA)?;
let motor2 = LargeMotor::get(MotorPort::OutB)?;
let motor3 = MediumMotor::get(MotorPort::OutC)?;

motor1.run_direct()?;
motor2.run_direct()?;
motor3.run_direct()?;

motor1.set_duty_cycle_sp(50)?;
motor2.set_duty_cycle_sp(70)?;
motor3.set_duty_cycle_sp(30)?;

motor1.stop()?;
motor2.stop()?;
motor3.stop()?;

What would be your intended use case? Would such a MotorSet struct be sufficient for it?

@karlmdavis
Copy link
Author

So, again, I'm pretty new to all this, but I'm seeing some driving behavior that I suspect is a timing issue. When I use this Python program, I notice that the robot "kicks" a bit to one side when it starts driving: https://github.com/ev3dev/ev3dev-lang-python-demo/blob/stretch/robots/EXPLOR3R/auto-drive.py

My initial guess here is that it's a timing issue: one wheel starts moving slightly before another, and that acts as a bit of accidental steering. I further guess/hope that if I update that code to use something like a MotorSet, instead, that the problem will go away. Lot of assumptions here, I know -- I only get a tiny bit of time every so often to play with this stuff.

My current mini project is rewriting that little program in Rust, so I was hoping to use a MotorSet or somesuch and avoid the question altogether.

@pixix4
Copy link
Owner

pixix4 commented Feb 4, 2021

Yes, such small "kicks" are a typical problem on ev3 robot and it is indeed a timing problem. Unfortunately a MotorSet cannot solve this problem. It is mostly used for convenience to reduce code size. Here is an example of the set_polarity function:

for motor in motors:
    motor.polarity = polarity

As you can see, this is basically the same implementation as the example code:

for m in motors:
    m.duty_cycle_sp = dc

However, it is possible to reduce these "kicks". First you should initialise all properties used, in particular duty_cycle_sp in your example. Both this and the python library use caching to improve the communication delay with the kernel drivers. At the first call to each property of a motor or sensor, a file handler is opened and stored. All subsequent calls to this property use the already saved file handler. To achieve this, you can add the following code between line 114 and 115 of your linked example.

for m in motors:
    m.duty_cycle_sp = 0

And a rust implementation of this example would reduce this "kick" too. Compared to python, rust is a compiled language and generally has better performance (this also applies to I/O operations).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants