Programming questions

So I am still waiting for my RVR to arrive (or even get a tracking number) here in the EU, but I set up a raspberry and took a dive into the code examples to get some ideas and build a plan for my project.

What took me as a surprise was that there are only examples for raw motor control or drive by time with a sleep afterwards. The RVR was advertised to be so intelligent to drive on any terrain and with integrated sensors be precise when driving over it.

So I wonder why there is no example that has a drive by distance?
Do we have to code this ourselves by streaming the sensor data and making sure it does not loose its heading and track the distance that it travels, then interrupting the movement if the desired distance is reached or doing some extra movement when it falls short? I really thought that this would be part of the internal controls to begin with.

And why is there no example that lets the RVR drive and wait for it to complete the command?
Sleeps are a bad way to work with when there is something physical executed, because the sleep time is always just a guess on how long it will take (well actually it is bad practice with any kind of API that executes something and waiting for it to complete). Does the API not support this? Have not seen an example to check if the motors are running or not, but that would be a start to make a loop with a millisecond or so sleep till the motors stopped running.

1 Like

Hey @RuyLightworks!

Sorry for the delay in getting back to you… In an effort to not continue to leave you hanging, I’ll address some of your questions while I am waiting on some answers from one of our schmancy engineers about why we made some of the decisions we did :slight_smile:

First of all, I am deeply sorry that you still haven’t received a tracking number for your RVR; I know that the factory we used this time around had some hiccups and some people received their RVRs before their tracking numbers :see_no_evil: I am not privy to information about such things, but reaching out to support@sphero.com would be the best way to have the same information we do about updates from the factory.

Re Driving: Luckily, the RVR is smart enough to drive precisely over any terrain! All of the videos where you see it doing so are 100% real. With that said, there are some edge case management stategies that our team is still working on for different terrians and accurately driving a set distance on them (but RVR is perfectly capable of driving straight over all terrains :slight_smile: ). Rest assured, this is still a feature of RVR that will be in a firmware update, coming soon!

In the meantime, we’ve been chatting with users about looking at the speed that their RVR travels (using the built in graphs in the app) over the terrians they are driving on and using that metric to calculate a time (no crawling on your hands and knees with a tape measure required :slight_smile: ).

Very much looking forward to seeing all that you accomplish with your RVR and I’ll get back to you on the python SDK questions shortly!

Kelsey

2 Likes

Thanks for the answer.

I am aware that with the build in sensors it is possible to do this on your own. Well don’t have one here so can’t analyse the data you get but essentially that is just math. But getting that over the serial channel, doing the calculations and sending commands back seems not the optimal way when the build in processor could do this directly. So I am glad to hear that this is coming.

Hope that there will also be some way to get info on what the RVR or motors are doing so you don’t have to rely on sleeps in the code and can actually wait for a command to complete. Also saw that there is just a stall check, but with an encoder build into the motors I guess it should be possible to get more information then that. Actual speed or steps made so code can compare that to the speed that was send to the RVR to check if one track is skipping.

I realize the RVR is still in the diapers so to speak, so there will be a lot more coming. Take this as suggestions for features that are very useful for us to have :wink:

About the delay in shipment. Well there was an announcement on the Kickstarter page a week ago that EU shipping was happening on that day or the day after. But if that was the case it should have arrived from anywhere in the EU already. Looks like a lot of people in the EU are still waiting on their RVR. Some communication on what is going on would really be nice here.

Looking forward to get my hands on the RVR soon to start my project. Basic framework on a Pi is already in work and ready for a few test cases :wink:

2 Likes

Hello @RuyLightworks

Regarding the timeouts you’ve noticed in our getting_started samples, this is due to the serial connection used while operating RVR with a Raspberry-Pi. Typically users operate our robots through their smartphones over bluetooth. This introduces an inherent latency that allows the firmware to process incoming packets at a rate the onboard chipset can handle without throttling. Since a serial connection is established at a baud rate of 115200, RVR’s chipset can now get flooded with commands coming in too quickly. RVR still needs to support operation over bluetooth, so the chipset is designed around it since it’s the most common use-case. We considered adding a throttled queue under the hood for this initial rollout of the SDK, but we noticed it introduced a slight delay in command processing. We plan on revisiting this concept at some point. For now timeouts are recommended for waking up, driving, and setting the LEDs.

RVR should be given at least 1 second after a wake command in order to ensure any subsequent commands are not ignored.

A single driving command lasts 2 seconds.

Driving, and LED commands can support timeouts as fast at .01.

In reference to a “drive by distance” command for RVR, it is something our firmware team has on their feature roadmap, but we don’t have a concrete timeline for rollout yet.

In lieu of that feature… you can use the Locator sensor stream which returns X and Y values of a local coordinate system.

When you power-up RVR, it creates a local coordinate system, and starts at 0,0 with RVR’s front pointing towards positive Y. The coordinates represent RVR’s position in meters. As RVR is issued driving commands, it updates its position in the coordinate system using the driving data the user provides. RVR does not update its internal position when it’s not driving. For example, if you were to pick it up after it stops, and position it elsewhere, it would resume from the last coordinates it reported.

Here’s a usage example of the Locator sensor stream:

from sphero_sdk import SpheroRvrObserver
from sphero_sdk import RvrStreamingServices

rvr = SpheroRvrObserver()

def locator_handler(locator_data):
    print('Locator data response: ', locator_data)

rvr.sensor_control.add_sensor_data_handler(
            service=RvrStreamingServices.locator,
            handler=locator_handler
)

rvr.reset_yaw()

rvr.sensor_control.start(interval=250)

rvr.drive_with_heading(speed=128, heading=0, flags=0)

There’s also an option to reset the internal coordinates back to 0,0. This can be done in two ways.
You can issue a command to reset the coordinates:

rvr.reset_locator_x_and_y()

You can also configure RVR to reset the coordinates every time rvr.reset_yaw() is invoked:

rvr.set_locator_flags(flags=1)

To disable this, issue the command with the flags parameter set to 0:

rvr.set_locator_flags(flags=0)

I hope this helps with the applications you have in mind. Happy coding!

EDIT: Typos & Code Errors

3 Likes

That is good information since I’m working over the serial port in C++. And, ahem, reminded someone about locator.

You might consider a command to enable / disable Bluetooth from the serial connection. It would only be good during that power cycle. Whether that makes sense I can’t say.

Is the Bluetooh (BLE) a serial connection using the same commands? If a computer has a BLE it could control the Rvr from my C++ work?

2 Likes

Thanks for the information.
I am on the same page as rmerriam there, if Bluetooth availability is the the issue then there should be a way to disable it. I guess any project where you drive the RVR with a raspberry or arduino doesn’t need the on device Bluetooth. I understand that waking up takes some time, but 2 seconds for a drive command… well 2 seconds in programming is a huge huge time.

About the delays, well how do we see when a drive command has been executed? I assumed that the delays were in the code for that. So lets say I give a command to drive 5m forward, then want to do something at that location. So I need to know when the drive has been completed. But if that is coded in a loop like “drive 2 seconds check if position is reached” there is a huge chance that I overshoot the desired location.
Also considering other applications like driving around and having a collision sensor. Well when for example an ultrasonic sensor detects there is a wall in front a delay of 2 seconds for a drive command can cause a crash to happen before we have a chance to prevent it.
Or lets say I want to drive in a semicircle. I could either slice down the circle into small chunks of straight lines to get close to the semicircle, but then it would be drive a little then wait till the 2 seconds are over? So essentially the RVR would be sitting still more then driving?
I have seen the drive with roll command, but this only shows the speed, start heading and end heading. So there seems to be no way to control the diameter of the semicircle?
If that would be done with raw motor control to set the outer track faster then the inner track there is again the issue of overshooting the desired target location.
Which reminds me, I have not seen a command in the API docs to stop. How can we cancel a drive command when for example we detect an obstruction with some external sensor?

About the helper and locator yes I have seen those examples. But what I am not sure about is if you give a command with a heading does the RVR make sure to keep that heading? So if it drives over a terrain where for example one track skips a bit does the RVR automatically compensate to keep its heading or does this result in the whole internal coordinate system to get rotated? If it keeps track of heading and compensates then this would be perfect, if not well then this is pretty much useless unless done in a controlled environment. I have worked with gyroscopes and accelerometers before so I thought about something like drive forward and if I detect that the heading shifts I compensate by adjusting the speed of the tracks. But there the delay for drive commands throws a stick in the gears again. To keep a straight line these have to be very fast, otherwise the end result would be a wave curve instead of a straight line.

Maybe I understand something wrong here but these are my thoughts on those topics at the moment.

2 Likes

@rmerriam

You might consider a command to enable / disable Bluetooth from the serial connection.

Ah yes, this would make sense. While this might be possible to do, it’s the processing speed of our chips that’s limiting factor, I’m afraid. This goes back to my point about designing around the most common use-case. I’m also completely glossing over the diligent work our electrical and mechanical teams put into the architecture, with the end result being a careful balance of features and cost.

Is the Bluetooh (BLE) a serial connection using the same commands? If a computer has a BLE it could control the Rvr from my C++ work?

The packets parsed by the RVR firmware are identical whether they are transmitted over bluetooth, or a serial connection. If you want to use bluetooth to control RVR without the use of our mobile apps, an additional platform-specific interface is required.

You could potentially write your own bluetooth communication bridge between a PC (or other device) and the Raspberry-pi connected to RVR. You would need to write a custom parser on the Pi that would translate the incoming data into commands that could then get issued to RVR through the python SDK and the serial connection.

On a related note, there’s an an example in our projects directory that uses a 2.4Ghz radio receiver connected to the Pi to essentially turn RVR into an RC vehicle with range far greater than Bluetooth. You can find it here.

EDIT: Also wanted to mention that it is possible to operate RVR with mobile device over bluetooth, while a Raspberry-Pi runs it’s own program over the serial port on RVR. As long as the Pi, and mobile device aren’t trying to issue the same type of commands, they could work in parallel without conflicts. For example, you could drive RVR through the Sphero EDU app, while the Pi controls connected external devices based on RVR sensor streams.

3 Likes

@RuyLightworks

To clarify the usage of driving timeouts, let’s say you wrote a simple program that issues one driving command to RVR, and nothing else. RVR would drive for 2 seconds and then stop, but it’s possible to issue driving commands at a much faster interval than every 2 seconds. Taking it further, if you wanted to write a program that drives RVR based on some type of input, then you could issue commands in an infinite loop with a timeout as fast as .01.

while driving_enabled:
    rvr.drive_with_heading(speed=input_speed, heading=input_heading, flags=0)
    time.sleep(.01)

This would allow for fast input response, such as driving with a controller, or keyboard, or even autonomous driving. We have an ultrasonic RVR project you can review for reference.

How can we cancel a drive command when for example we detect an obstruction with some external sensor?

You can stop RVR on a dime with:
rvr.raw_motors(left_speed=0, left_mode=0, right_speed=0, right_mode=0)

You can also use the driving control to issue a roll_stop command. The heading parameter is absolute, based on the last time the yaw was reset:
rvr.drive_control.roll_stop(heading=0)

So lets say I give a command to drive 5m forward, then want to do something at that location. So I need to know when the drive has been completed. But if that is coded in a loop like “drive 2 seconds check if position is reached” there is a huge chance that I overshoot the desired location.

Keeping in mind that you can issue driving commands as fast as every .01 seconds, and then stop with the aforementioned command, you can accomplish this through the usage of the “Locator” stream. You would need to write logic to calculate the distance.

But what I am not sure about is if you give a command with a heading does the RVR make sure to keep that heading?

Yes, RVR will maintain its heading based on IMU feedback, even if it collides with an obstacle and is temporarily knocked off course.

2 Likes

Thanks for the explanations.
Clears up some stuff that I was thinking about. Maintaining heading and the locator should make it very easy to drive the RVR along a set path with absolute distances.

Only thing I am still thinking about now is finding a solution for the semicircle or bend/curve driving. Not sure the command that exists can do this, cause I don’t see a way to control the radius it drives. So as an example I want to make the RVR drive in a pattern that represents the Sphero logo. For the outer line that would be a nearly full circle with that little spike to the top left. Then a complete inner circle. Then two ovals with different sizes for the eyes. I know I can break that down into very small straight segments like a 3d printer does (did some programming there too so should be easy to do) or is there a way to do that with the drive with roll command somehow?

1 Like

:wink: You’re new around here, aren’t you? :wink: Just teasing.

I’m a bit infamous on here since I’m reverse engineering the protocol using C++. Currently using a USB to 3.3v serial port dongle. Also have it working with a serial connection to an Up Board. Interesting that I could eliminate the dongle and use Bluetooth. A quick test gets a pairing and connection but the serial port stops responding. Running Linux so must be missing an incantation to make it fully work. Would be interesting to eliminate the serial cable for this work. I can remote debug over WiFi to the Up board if I get to needing mobility.

1 Like

@RuyLightworks, there is a Robotic Operating System (ROS) used for developing robotics systems. I mention because your attempt to drive in curves is what ROS calls a twist. This command has two parameters: linear speed and angular rate. It tells the robot how fast to move (linear) and a turning rate (angular). So you might specify moving at 50% speed and 20 degrees per second which will move the robot in a circle. Eventually I will figure out the calculations for this with the RVR. Basically you have to calculate the difference in the left and right motor speeds to cause the angular rate.

Update:

Here is the info on doing twist and tank (or differential) drive calculations.

Tank to Twist Calculation

When a left and right joystick inputs are received by the drive_teleop node, representing left and right wheel velocities (ie. skid steering or differential drive), a geometry_msgs/Twist with linear and rotational velocities is calculated as:

Linear velocity (m/s) = (left_speed + right_speed) / 2.0
Angular velocity (rad/s) = (right_speed - left_speed) / 2.0

Twist to Tank Calculation

When a geometry_msgs/Twist containing linear and rotational velocities is received by the drive_firmware, wheel velocities are calculated as:

Left wheel velocity (m/s) = linear_speed + angular_speed
Right wheel velocity (m/s) = linear_speed - angular_speed

That is from ROS Simple Drive

2 Likes

@rmerriam thanks for the link. That looks like it can be very useful for some stuff.
Yes I knew there are calculations you can do to do this with raw motor control. Only thing that will be a little bit of a problem is that this is just the math, but out in the environment you need to add in error correction for terrain too. So you need to check all the time if the calculated speeds are still correct or control the heading. I don’t know if the RVR has something build in with those commands. So when you use the raw commands to set one track to speed x and the other to speed y if it keeps these speeds even if one track goes over sand and slips a bit.

There is this example I was talking about which looks a bit like driving a curve. But this looks more like you tell the RVR what the end heading should be and you have not much influence on the path it drives.
await rvr.drive_control.reset_heading()

    await rvr.drive_control.roll_start(
        speed=64,
        heading=90
    )

    # Delay to allow RVR to drive
    await asyncio.sleep(1)

    await rvr.drive_control.roll_stop(heading=270)

    # Delay to allow RVR to drive
    await asyncio.sleep(1)
1 Like

My experience is what you’ve seen. The RVR turns to the heading and then drives straight. The stop also changes the heading, because is is just drive(0, heading).

Driving on rough terrain is a real challenge. I doubt the RVR automatically adjusts for this. I don’t imagine any of the big boy robots do well on that problem.

2 Likes

Ok, so the roll_start is just a convenience function to combine turning then driving. I wish there was a little bit more documentation on these functions :wink:

Well there are robots that handle this quite well look at what some of the moon/mars rovers can do or what Boston Dynamics does, but I don’t expect pinpoint accuracy from the RVR. But some way to have a reasonable level of error correction would be nice.

1 Like

The big boys are using visual cues and other inputs. Interplanetary rovers move very slowly annd aren’t really on rough terrain. Don’t mean to be argumentative, just clarifying.

1 Like

Hi @RuyLightworks, I’d like to clarify things a bit from a firmware and electrical perspective. The raw motor commands are simply setting the PWM duty cycle(1) to the motors. A raw motor command of 255 is providing 100% duty cycle PWM to the motor driver IC. 127 would be 50% duty cycle, etc. When you use raw motor commands, you’re actually bypassing the RVR’s on-board control system. By doing this and using the locator streaming interface, you can build your own complete control system externally. However, communication bandwidth limitations will mean that an external system cannot respond to errors anywhere near as quickly as the internal control system.

Since it sounds like you’ve done a fair amount of robotics programming in the past (including some motor control?) you may already know the following, but here’s some background just in case:

  • Duty cycle is the fractional or percentage on-time of a digital signal. So a square wave with a period of 100 ms that is high for 50 ms would be a 50% duty cycle, 30 ms on-time would be 30% duty cycle, etc.
  • Pulse width modulation, or PWM, is the method of varying the duty cycle of a digital signal to achieve an average signal level between 0 and 1.
  • As in most variable output motor drive systems, RVR’s motors are driven with a PWM signal, and varying the duty cycle of that signal effectively scales the voltage applied to the motor: given duty cycle D, and battery voltage Vbat, Vmotor = Vbat * D
  • Motors (at least ones with permanent magnets like the brushed motors in RVR) act as generators any time they are spinning, and generate a higher voltage as they turn faster.
  • In steady state conditions (i.e. not starting or stopping, with constant load torque and constant voltage), the voltage applied to the motor is split between driving current through the winding to generate torque, and overcoming the internally generated voltage, called the back EMF. There is a single equilibrium rotational speed for any given combination of voltage and load torque. Transient conditions are more complicated - if you google DC motor control you’ll be able to find lots of resources to learn more about this.
  • Any variation in loading of the motors due to surface friction changes, inclines, obstacles, etc will shift the equilibrium point of the motor. This is why we use closed-loop feedback control for any motor application that requires precision.

Here’s the good news:
The initial RVR firmware release supports only 1 drive command, the roll command that you’ve been reading about. It’s fine for driving with a joystick using absolute headings, but we have multiple other driving interfaces in the works that will fit much better with what you’re trying to accomplish. So while you could go to the trouble of creating a low-bandwidth external control system, you can also use the time before the next firmware update to get more familiar with our SDKs and then make use of the new driving interfaces when they become available. We are also working to improve performance with the existing roll command interface.

(1) Although you can directly control the duty cycle provided to the motor driver IC, the driver will chop its output to limit the motor current. This means that there are corner cases (low speed, high load, specifically) where the duty cycle of the PWM signal coming out of the general-purpose processor is lowered by the current limiting mechanism.

6 Likes

I haven’t done much robot programming yet apart from some robot arm controls but quite familiar with motor controls in general. Did some stuff with 3d printer controls, that uses stepper motors but the math behind movements is the same. So yes I know the stuff about PWM and DC motor control. But nice that you sum it up here for anyone reading this.

Didn’t know that the raw commands completely bypass the controls. Something in between where the encoders are used too to set a certain rotation speed for the motors might be a nice idea to have too.
Guess I will start with the normal drive commands and locator to implement straight driving and see what you have in store with the new driving interfaces you are working on. For curves I can put in a function that slices up the curve into small straight lines to get a close result and maybe later drop in a proper curve drive command there. Think modular programming is the key here anyways to be able to react to changed and make use of improvements easily.

Is there any rough estimate on when you will release the next update? Do you have some kind of roadmap online that people can check out for this kind of stuff? Might be a nice idea to let people see what is coming. Don’t expect exact release dates or anything, but an estimate like Q1 2020 or something like that would be nice to know.

2 Likes

Hey @RuyLightworks!

Thanks for chatting through all of this with us :slight_smile:

After chatting with the team, I can give you a rough estimate that we are shooting for the next FW update to be released sometime in Q1 of 2020, with our current pace and development priorities. As with anything in development, there is always a possibility that priorities will shift based on requests and feedback from users, but this seems like something that our users are excited to utilize (and we are excited to release!).

Thank you again for enabling us to have such a fun and engaging discussion!

Kelsey

2 Likes

I am trying to use the locator data, can print it out but have no clue how to get the actual values to work with.
The locator_data is some unknown object and I don’t get what it is (maybe my python knowledge is a bit too slim for that).
Tried:

for elem in locator_data:
    print(elem)

and I just get “Locator”
Then tried:

for elem in dir(locator_data):
    print(elem)

which gives me:

__ class__
__ contains__
__ delattr__
__ delitem__
__ dir__
__ doc__
__ eq__
__ format__
__ ge__
__ getattribute__
__ getitem__
__ gt__
__ hash__
__ init__
__ init_subclass__
__ iter__
__ le__
__ len__
__ lt__
__ ne__
__ new__
__ reduce__
__ reduce_ex__
__ repr__
__ setattr__
__ setitem__
__ sizeof__
__ str__
__ subclasshook__
clear
copy
fromkeys
get
items
keys
pop
popitem
setdefault
update
values

Lo it looked like a dictionary of sorts, but iterating over the keys does not work.
The print says something like:
Locator data response: {‘Locator’: {‘is_valid’: True, ‘X’: 28416, ‘Y’: 68864}}
So thought these are keys, but locator_data[‘is_valid’] doesn’t work either.

Anyone knows what kind of object this is and how to get the is_valid, X and Y ?

Edit: Oh and what kind of measurement are these values? the above line was just driving 1 second with speed 64. So 68864 is quit a big number… can’t be mm. So are these steps? Would need a distance measurement here.

1 Like