rover using ROS navigation stack is not aggressive enough

1,106 views
Skip to first unread message

Tom Bertalan

unread,
Dec 2, 2016, 11:11:20 AM12/2/16
to HomeBrew Robotics Club

Hello guys--I'm not sure whether I should be asking this here or on answers.ros.org, but I'd like to introduce myself here as well, so I figured I'd do both things in one post.


I've been making a small (~1 square foot) differential-drive rover with a tail caster, two motor encoders, and an XV11(/21?) LIDAR mounted on top. It's powered by a Raspberry Pi 3, which handles encoder integration, sends motor commands by GPIO to a dagu 5 motor board, and runs roscore, but, at Jeff's suggestion, I'm running gmapping and the navigation on a separate (i7) desktop, over a reasonably strong wifi link. My map tuning could use some work for sure, but at the moment I'm trying to do a pretty simple drive-forward-and-to-the-right-1-meter task. The specific problem I'm having is that the robot refuses to go beyond its stated minimum velocities, which I assumed are the lowest speeds achievable before static friction takes over. I've tried bumping acc_lim_x to ridiculous levels, to no effect.

The environment looks something like this:


And the robot something like this:



Additionally, it seems fixated on doing clearing rotations. Where should I be entering recovery_behavior_enabled: false and clearing_rotation_allowed: false? Currently they're at the top level of a yaml file which is loaded between the tags for the move_base node in my planning launch file. [edit] Actually, watching the output for that launch, it seems slow in-place rotation happens not when a recovery behavior is started, but when I get a series of messages like:
Costmap2DROS transform timeout. Current time: 1480694301.9495, global_pose stamp: 1480694300.4478, tolerance: 1.5000
[ WARN] [1480694301.949696142]: Unable to get starting pose of robot, unable to create global plan
[ WARN] [1480694302.026249684]: Could not get robot pose, cancelling reconfiguration
[ WARN] [1480694302.282950941]: Unable to get starting pose of robot, unable to create global plan
[ WARN] [1480694302.616289437]: Unable to get starting pose of robot, unable to create global plan
Any suggestions for how to prevent this?

I think I've suppressed the recovery behaviors, but I still get
[ INFO] [1480694507.946145567]: Recovery behavior will clear layer obstacles

at the start of the launch.

Additionally additionally, in order to let a 2d navigation goal be attempted, i need to submit it in rviz, but then closed rviz, as it seems to inhibit nonzero cmd_vel messages. What is the recommended way to prioritize navigation control of cmd_vel when joystick input is zero? The yujin_ocs cmd_vel_mux node? It would be nice to be able to monitor the local and global plans. 

As for introducing myself--I'm a PhD candidate in engineering and applied math in the northeast, with research interests in dimensionality reduction for complex heterogeneous dynamical systems (mostly biological neural networks). I'd love to start hacking more on the internals of gmapping and the navigation stack, and maybe put a bit of my training to use, but I'd like to get it working with the existing software first!

Tom Bertalan

Ralph Gnauck

unread,
Dec 2, 2016, 1:15:13 PM12/2/16
to hbrob...@googlegroups.com
Tom, welcome to the HBRC.

I can give you a few tips on using the planners.

Make sue your base driver node is actual controlling the robot at the correct speeds.
Try just sending cmd_vel messages to the robot from the command line without move_base nodes running and ensure the robot runs the the commanded speed.
In ROS speeds are in m/s and rad/sec,  i.e. send it a 0.5m/s command and verify it is actually going at that speed by timing it over a measured distance.

Also try to determine what the min/max linear and angular velocities/accelerations  that your robot can actually achieve are, you should set the planner parameters to be as close to the real limits as you can.
The planner works in 'Velocity Space' so these parameters are important. This means that the planner trys to determine a path for the robot and simulates it by giving the model of the robot certain velocity commands to make it move. It assumes the robot will actual obey these commands accurately, if your real robot then does not respond in a reasonably similar way it will not get to the locations the planner expects in the assumed time and the planner will keep stopping and recalculating new trajectories.

Rotations are an issue, make sure the lidar is not getting interference from any parts of the robot.  
I think the initial clearing is normal, see the config files in the  intro_to_ros project mentioned below for an example of the yaml files for configuring the planners.

As to the Nav stack competing with the joy stick, you should use the cmd_velocity_mux node



Take a look at the intro_to_ros project on github 



It has a set of config files and launch files for a similar robot (neato botvac80 base using a Raspberry PI controller).  You may find some helpful configurations in there that would work (or be a good starting point) for your bot also.


Again welcome to the HBRC, looks like a nice robot.

Good Luck

Ralph

From: Tom Bertalan <t...@tombertalan.com>
To: HomeBrew Robotics Club <hbrob...@googlegroups.com>
Sent: Friday, December 2, 2016 8:09 AM
Subject: [HBRobotics] rover using ROS navigation stack is not aggressive enough

--
You received this message because you are subscribed to the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+...@googlegroups.com.
To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.


Ralph Gnauck

unread,
Dec 2, 2016, 1:23:36 PM12/2/16
to hbrob...@googlegroups.com
Hi Tom

Just thought of some more items that may help.

The issue with the 'starting pose' may be one of a number of things.

Are the clocks on the Laptop and your Raspberry PI synchronized, ROS is very finicky about the timing, 
Make sure you are running chrony on both computers and that they are synchronizing properly to each other.


Also - make sure that the planner is properly localized before trying to send it a navigation target.


Also - as you are running on a PI the default map size may need to be reduced, the default is about 10mx10m and that needs a large amount of memory and processing, try reducing the map size to something just big enough to contain your actual map.

Also since the PI is not as fast as a PC you may need to reduce the update and publishing frequencies in the planner config, on a PI 2 we need to reduce that to about only every half second or so.

Hope this helps

Ralph







From: Tom Bertalan <t...@tombertalan.com>
To: HomeBrew Robotics Club <hbrob...@googlegroups.com>
Sent: Friday, December 2, 2016 8:09 AM
Subject: [HBRobotics] rover using ROS navigation stack is not aggressive enough

Tom Bertalan

unread,
Dec 3, 2016, 9:15:28 PM12/3/16
to HomeBrew Robotics Club, ralp...@pacbell.net
Thank you both for your replies. Gnaur had it--I needed to accept cmd_vel data in real units of m/s and rad/s. For some reason, I had assumed they were in arbitrary units, and chose a range that worked well with the built-in teleop panel in rviz. This worked out to very small values providing reasonable movement. I've since dumped the rviz teleop, and reverted to the simple teleop_twist_keyboard package. I spent about an hour sending Twist messages with rostopic pub and driving forward beside a tape measure or turning in place, and came up with a new set of parameters to use in my twistToMotors script. With my inputs to cmd_vel properly scaled to represent real units, I get believable waypoint seeking.

I also discovered the problem with rviz zeroing my cmd_vel topic, and hence being incompatible with move_base--despite removing the telop panel from the interface and saving configuration, there was still a section in my ~/.rviz/default.rviz file (which I found by grepping for cmd_vel). Deleting this allowed rviz to coexist with other cmd_vel sources, like move_base or teleop_twist_keyboard. The problem of setting up cmd_vel_mux is less urgent now, but I'll probably still take it up eventually.

I don't think time difference or initial localization is a problem--assuming in the latter case that this initial localization is that provided from gmapping. However, I'll remember those in case they become relevant in the future. As mentioned before, both mapping and navigation occur on the i7 workstation, with no subscribers on the rpi, so I don't think bandwidth or memory should be a problem any more. But I still do need to send LaserScan messages from the rpi back to the workstation, which I imagine are a little heavier.

I still have some problems with recovery behaviors, but of a different sort--It's hard to tell what behavior it's in at any given moment, since there's not much console output from my path_planning.launch. However, running rostopic echo /cmd_vel seems to demonstrate that the reverse-driving escape behavior dominates. This is problem since it activates when we're near to and nearly parallel to a wall, but turned a little away from it--our back will hit the wall, and the recovery behavior will make no headway. I tried the (unrecommended) practice of setting escape_vel: 0.1 (positive), and predictably ran into the opposite problem. Is there any way I can get a little smarter recovery behavior? See my yaml files here.

Relatedly, I think this problem would come up less if the global planner wouldn't try to drive so close to corners. Is there any way I can encourage it to drive down the middle of hallways and take corners wide instead?

It's entirely possible that some parameters are in the wrong yaml file or scoped to the wrong namespace--I don't know how I would have know to use the namespace TrajectoryPlannerROS for e.g. min_vel_x if it wasn't demonstrated in a sample launch file. Other base_local_planner parameters like occdist_scale I think should go in the same section of the same yaml file, but I'm not sure if that then makes them only apply to the local planner, not the global one. I see in the sample project that Gnaur linked that DWAPlannerROS is used instead. Is there some principled way I could enumerate these different base_local_planner namespaces?

Thanks again for your help! I expect my next steps will be replacing my loosening motor mounts, and doing some testing in some other environments. I want to have a quick-to-setup demo that I can show to the kids at the meeting of a local FIRST robotics team.

Tom Bertalan

unread,
Dec 4, 2016, 2:04:21 PM12/4/16
to HomeBrew Robotics Club, ralp...@pacbell.net
As a followup--I realized that my point about bandwidth probably didn't stand with the ros master running on the rpi. So, I moved it to the workstation, and I think motion was a little more fluid, though the effect of parameters like inflation_radius seems to have changed (the rpi is running Raspbian Jessie, on which only indigo is available, and the workstation is running Ubuntu 16.04 Xenial, on which only kinetic is available).

In the following, I experimented at several points with different scale factors.

These scale factors were added in eeb27e

At various points in the hallway and the entryways to the two bedrooms, you can see him get stuck in his backup-escape behavior, and I need to free him with a manual burst of forward teleop.

jsam...@pobox.com

unread,
Dec 4, 2016, 9:10:48 PM12/4/16
to hbrob...@googlegroups.com

On 12/03/2016 05:04 PM, Tom Bertalan wrote:

I've since dumped the rviz teleop, and reverted to the simple teleop_twist_keyboard package.

I didn't know you could do teleop from rviz...

I prefer to run the joystick teleop since it only publishes when hold down the button and it gives more precise control than keyboard teleop.



As mentioned before, both mapping and navigation occur on the i7 workstation, with no subscribers on the rpi, so I don't think bandwidth or memory should be a problem any more. But I still do need to send LaserScan messages from the rpi back to the workstation, which I imagine are a little heavier.

I assume that if you are running both gmapping and navigation at the same time that you are not running AMCL. If running both, you want only gmapping to supply the localization. Otherwise the two will fight by both supplying localization correction.

You mentioned earlier "It's powered by a Raspberry Pi 3, which handles encoder integration, sends motor commands by GPIO to a dagu 5 motor board" and you mentioned in the comments here:

https://www.youtube.com/watch?v=fTj2EdGO4Sk

"I suspect that some of my problems might just stem from poor build quality (my motor mounts are somewhat floppy), and dropping odometry data (my encoder interrupt-reading code is all in Python, and my interrupt services routines seem to take something like 3/100 sec, which is pretty terrible)."

I prefer to run a dedicated microcontroller to interface to the motors. You can get better odometry and you can even put PID control loops in the micro to get real time control of the motors. In my setup I send actual velocity commands to the micro (in m/s and rad/s) and it scales to motor counts and performs closed loop control of the velocities. I also prefer to use a microcontroller with hardware quadrature decode as opposed to software quadrature decode. People do seem to make software decode work, but using hardware is one less thing to worry about.

You can see in your videos that your odometry is a problem. The odom tf maker should start out on top of your map tf marker and then slowly vary around the map marker. In your videos you can see the odom marker is a long way from your map marker. And in this video (at around 4:50 to 6:00):

https://youtu.be/eSeLW9Hkjhc

You can see the odom marker wildly jumping around (at the top of the image).

So I think it would be worth the trouble to improve the odometry info. (when you get time) But is amazing to see how well the ROS localization is correcting the bad odometry in real time.

- Jeff Sampson

Tom Bertalan

unread,
Dec 4, 2016, 10:30:55 PM12/4/16
to hbrob...@googlegroups.com
I assume that if you are running both gmapping and navigation at the same time that you are not running AMCL. 
Yes, just gmapping, no AMCL.

I prefer to run a dedicated microcontroller to interface to the motors. You can get better odometry and you can even put PID control loops in the micro to get real time control of the motors. In my setup I send actual velocity commands to the micro (in m/s and rad/s) and it scales to motor counts and performs closed loop control of the velocities. I also prefer to use a microcontroller with hardware quadrature decode as opposed to software quadrature decode. People do seem to make software decode work, but using hardware is one less thing to worry about.
I think this actually should be my next priority. Do you have a suggestion for such a board? Preferably with some sample embedded code as well integrating the PID, encoder reading, and messaging, the combined timing of which could be hard to get right (interrupts and serial communication don't go together well on Arduino). Alternately I could use one or more of the Arduino pro minis I have lying around. Do you connect the board by serial, or something else like I2C or SPI?


I've also ordered some scooter wheels on the theory that they'll be easier to odometrize than the big squishy wild thumper tires.

Chris Albertson

unread,
Dec 4, 2016, 10:35:47 PM12/4/16
to hbrob...@googlegroups.com
"I suspect that some of my problems might just stem from poor build quality (my motor mounts are somewhat floppy), and dropping odometry data (my encoder interrupt-reading code is all in Python, and my interrupt services routines seem to take something like 3/100 sec, which is pretty terrible)."

At 3/100 sec you odometer system can handle no more than about 30 steps per second.  This means odometer is not working at all.    Try disconnecting odometry and not using it at all.  Run "open loop" and see what happens.

The best way to fix this is to get a small micro controller.  I like the ARM Cortex-M types.  You can pickup a small SBC for under $10
A small ARM can run two PID loops to control wheel speed.   Make the PID loops run in units of "encoder ticks per second"   All they do is read speed commands for the Raspberry Pi and make the commanded sped the current set point in the PID controller and on request send back the current encoder tick count.     
--

Chris Albertson
Redondo Beach, California

jsam...@pobox.com

unread,
Dec 5, 2016, 1:31:51 AM12/5/16
to hbrob...@googlegroups.com

I use an Atmel XMega chip on a custom board. I plan to port that over to a $12 TI TM4C123G LaunchPad when I have the ambition. But I don't have that yet.

It looks like ros_arduino_bridge might work:

https://www.youtube.com/watch?v=us9v9eIxH64

http://wiki.ros.org/ros_arduino_bridge

I haven't used it. Maybe Alan or Patrick could comment on that. I would think it could be connected to your existing motor drivers. Or somebody could figure out how to connect it if it is not directly compatible. Also I don't recall if that expects the 3 channel quadrature decode shield or if the encoders can be connected directly to the Arduino. But that would be an approach with plenty of support.

The scooter tires should have a curved surface and give you a smaller contact point, which will give better odometry data.

Tom Bertalan

unread,
Dec 5, 2016, 1:32:01 AM12/5/16
to hbrob...@googlegroups.com
Chris,

Actually, I don't think it's quite as pessimistic as that--default controller_frequency for move_base is 20 Hz, and I have it reduced to 5, while my odom topic (and transform) is publishing at 10 Hz. I could try running without odometry, but I don't think gmapping is set up to allow this--you need to be publishing some sort of transform from the odom frame to the base_link frame, and publishing a static tf would also be a constant source of error to be corrected. However, maybe there's a way to configure gmapping to compute the transform from /map to /base_link directly; I'll look into it.

Do you have a specific board recommendation? Some suggested model code? How would communication be done with the raspberry pi? I used an arduino mega for a while for handling motor commands and integrating odometry, but was having a hard time balancing interrupt handling with serial communication.

On second thought, though, I don't think that the speed of the rpi should be an inherent limiter on the fluidity of my encoder counting, and even PID speed control, which I was thinking of adding. This is very simple O(1) program we're talking about (not something horrendous like SLAM), and a 1.2GHz processor (not the 16MHz arduino). The limits would be IO--both on the rpi GPIOs (which I doubt are the problem) and in publishing to ROS. I'll do some more careful average-rate timing tests to see where I really stand; my methodology for getting the previous figure had some obvious flaws (like print statements and explicit calls to time.time() every loop). Maybe I can yet get away with my python odometry code on the rpi, with some tweaking.

Thanks for writing back; I'm really wondering why I didn't speak up on a community such as this long ago. Good stuff.

Tom

--
You received this message because you are subscribed to a topic in the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/hbrobotics/fdwI0QruEMI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to hbrobotics+...@googlegroups.com.

Chris Albertson

unread,
Dec 5, 2016, 12:41:35 PM12/5/16
to hbrob...@googlegroups.com
What is your expected encoder interrupt rate?   In my case I have a motor with 16 pulses per revolution and a 100:1 gear reduction.   If I run at 60 RPM at the wheel that is one revolution per second.  This means my rover is moving at about 0.3 meters/second.    It also means I should expect 1600 encoder pulses per second.   

Of course those numbers only work for one of my rovers and likely not yours but you can do the same kind of math and get an expected number of pules per second.   You have to work it out for the highest speed you want to drive at.   In my case this is 100 RPM so it is closer to 2,000 pulses per second.   But with two wheel encoders your processor sees 4,000 interrupts per second

So you can see that if my processor took 3/100 seconds per interrupt odometry would be impossible

One solution you might think would be to reduce the number of pulses per wheel revolution so that 3/100 can work   But now the PID velocity controller sees so few pulses that we can make a 20% change in velocity and the number of pulses per PID loop cycle remains the same.  The PID loop is then useless if it is based on counting pluses.  You would like for there to be a change in the court even for a 1% change in speed

What to build is a motor controller that accepts wheel velocity commands and sends the encoder count.   I would have it run on units of "encoder ticks" because the uP may not be so good at floating point math  and then will not have access to the ROS parameter server.

Keep the protocol simple, the uP reads a velocity set point at whatever rate that they are sent and always responds with the current encoder count.

Which ARM Cortex M board?    TI Lauchpad is neat in that that cost about $10 and you can program them with Arduino-like IDE.  The MBed platform 
is more powerful and not much harder to use and is multi-vendor and gives you a small RTOS.   An ARM running at 80MHz has zero trouble with high interrupt rates and multitasking under an RTOS

OK, a way to long explanation for "hat is your expected encoder interrupt rate?"  but I just can't see how a slow handler even work at alll. 

To unsubscribe from this group and all its topics, send an email to hbrobotics+unsubscribe@googlegroups.com.

To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+unsubscribe@googlegroups.com.

To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.

Tom Bertalan

unread,
Dec 5, 2016, 1:10:31 PM12/5/16
to hbrob...@googlegroups.com
Chris,

I'm using the Pololu 172:1 Metal Gearmotor 25Dx56L mm LP 6V with 48 CPR Encoder, running at 1/4 resolution (only attaching my ISR for rising edges on one of the two channels). So, that's 48/4*172/60*100=3440 ticks per second at 60 RPM. So, if my ISR takes .03 seconds, I should be handling only every 103rd tick, which I agree should give garbage results. Empirically, it seems to basically work, so I must be doing better than .03 seconds--I'll check properly tonight.

If I'm going to do the ISRs in python, then I should at least separate it into two nodes, so I don't run afoul of the GIL. The OS should be able to handle that concurrency pretty smoothly. I could then make a third, separate, node to integrate this into odometry, perhaps at a slightly slower rate (and maybe another for PID; perhaps directly integrated with the motor control script; perhaps not).

I'll put a little more effort into attempting to handle encoders on the rpi, and then try the launchpad or mbed. I suppose the idea would be to use a simple serial hand-designed bytesteam to communicate with the uP? It would check for input and send encoder totals every 10 ms or so; otherwise be sleeping for ISR callbacks.

Tom

To unsubscribe from this group and all its topics, send an email to hbrobotics+...@googlegroups.com.

To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+...@googlegroups.com.

To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.



--

Chris Albertson
Redondo Beach, California

--
You received this message because you are subscribed to a topic in the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/hbrobotics/fdwI0QruEMI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to hbrobotics+...@googlegroups.com.

Bob Smith

unread,
Dec 5, 2016, 2:48:00 PM12/5/16
to hbrob...@googlegroups.com
On 12/05/2016 10:04 AM, Tom Bertalan wrote:
> I'm using the Pololu 172:1 Metal Gearmotor 25Dx56L mm LP 6V with 48 CPR
> Encoder <https://www.pololu.com/product/2288>, running at 1/4 resolution
> (only attaching my ISR for rising edges on one of the two channels). So,
> that's 48/4*172/60*100=3440 ticks per second at 60 RPM. So, if my ISR takes
> .03 seconds, I should be handling only every 103rd tick, which I agree
> should give garbage results. Empirically, it seems to basically work, so I
> must be doing better than .03 seconds--I'll check properly tonight.

Slilghtly off topic but what if you ran the quadrature
pulses into a counter. Use the carry out of the counter
to generate an interrupt. You can vary how often you see
an interrupt by controlling the number of bits in the
counter.

Take a _timestamp_ on each interrupt. Subtract the previous
timestamp from the current one to get the period. Divide
the period by the max count of the counter to get the period
per pulse. Invert to get the frequency. The accuracy of this
approach is based on the accuracy of your computer's timebase.

There are "programmable divide by N" chips in the 74LSxxx
series that would let you select how often there is a carry
out from the counter. You could use GPIO lines to control
the "N" in the divide-by-N counter.

As I mentioned, this use-period-instead-of-frequency discussion
is slightly off topic.

Bob Smith

Tom Bertalan

unread,
Dec 5, 2016, 6:02:45 PM12/5/16
to hbrob...@googlegroups.com
Chris, which TI Launchpad in particular were you talking about? There are quite a few options, all reasonably priced for a single purchase. Lots of interesting features are on display. Mouser says the Tiva C series has "two quadrature encoder inputs". That seems to apply only to those boards based on the TM4C213x MCUs, such as the TM4C123GH6PM ($13 on mouser) (others have only one QEI).

There are also some boards (like the LAUNCHXL-F28069M, $25 from TI or Digikey) which have ROM containing TI's "InstaSpin-Motion" motor control libraries. Bizarrely, the product page doesn't mention a clock speed. I'm thinking this is not the board for me. 

As for mbed, Sparkfun sells the LPC1768 Cortex-M3 (which was also the top result on Amazon, for more $), so I'm guessing that's a good choice. The mbed environment seems quite civilized, and includes a pip-installable toolchain.

Both seem to have much better IDE support that Arduino, and compilation by makefile doesn't look like it would be such an ugly hack, which is nice. But the launchpad seems to actually allow debugging (what a novel concept).

Bob, neat idea. This would work if you only cared about the magnitude of your motor speed. If you want direction as well, you need to do a little logic with the actual instantaneous values of the two encoder square waves, which is different depending on whether you're doing quarter-, half-, or full-resolution. I'd bet that this logic is pretty easy (for one knowledgeable; not me) to implement in discrete components, and so could be combined with a few of those accumulators to get an ultra-fast encoder counting circuit. OTOH, this whole circuit surely exists as an IC for purchase somewhere.

Tom

Bob Smith

unread,
Dec 5, 2016, 6:51:16 PM12/5/16
to hbrob...@googlegroups.com
On 12/05/2016 01:55 PM, Tom Bertalan wrote:
> Bob, neat idea. This would work if you only cared about the magnitude of
> your motor speed. If you want direction as well, you need to do a little
> logic with the actual instantaneous values of the two encoder square waves,
> which is different depending on whether you're doing quarter-, half-, or
> full-resolution. I'd bet that this logic is pretty easy (for one
> knowledgeable; not me) to implement in discrete components, and so could be
> combined with a few of those accumulators to get an ultra-fast encoder
> counting circuit. OTOH, this whole circuit surely exists as an IC for
> purchase somewhere.

Agreed, you would want an up/down counter with
steering logic to set up or down mode. Doable
but more logic.

I've never seen a chip anything like this short
of an FPGA or CPLD.

BTW: you can configure the GPIO lines on the RPi3
to cause select to return when the input value
changes. (But you already knew this, right?)
I'm working a minor driver tweak so that the
interrupt handler captures a timestamp so we
can get really accurate time measurements.

thanks
Bob Smith

Ralph Gnauck

unread,
Dec 5, 2016, 7:19:54 PM12/5/16
to hbrob...@googlegroups.com
Tom,

I have used a couple for small robot projects an the encoder peripherals are very handy.

These are 80Mhz parts.

I use them on windows and you get to download the TI CodeComposer studio IDE (eclipse based - probably  works in linux also).
This supports full C/C++ development and debugging, and these boards have a built in Programmer debugger so you don't need anything else to get going with them.

The nice thing about the chips is that the Quadrature Encoder peripherals also allow you to get a velocity estimate from hardware as well as the distance and direction. 
They ave build in USB serial interfaces so talking to your PI is easy (or you can use the UART directly as TTL signals).

Ralph







From: Tom Bertalan <bert...@princeton.edu>
To: hbrob...@googlegroups.com
Sent: Monday, December 5, 2016 1:55 PM
Subject: Re: [HBRobotics] rover using ROS navigation stack is not aggressive enough

--
You received this message because you are subscribed to the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+...@googlegroups.com.

Tom Bertalan

unread,
Dec 5, 2016, 7:54:09 PM12/5/16
to hbrob...@googlegroups.com

I use RPi.GPIO.add_event_detect to register an interrupt service routine. Not sure which "select" function you mean.

You can see the code here: https://github.com/tsbertalan/gunnar/blob/master/src/gunnar/motor.py

In this commit you can see the transition from full resolution to quarter: https://github.com/tsbertalan/gunnar/commit/9250481221e56eb189a8d0ba7af5bf42bc1c51cc

Which driver are you tweaking?


--
You received this message because you are subscribed to a topic in the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/hbrobotics/fdwI0QruEMI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to hbrobotics+...@googlegroups.com.

Chris Albertson

unread,
Dec 5, 2016, 8:08:43 PM12/5/16
to hbrob...@googlegroups.com
On Mon, Dec 5, 2016 at 10:04 AM, Tom Bertalan <bert...@princeton.edu> wrote:

I'll put a little more effort into attempting to handle encoders on the rpi, and then try the launchpad or mbed. I suppose the idea would be to use a simple serial hand-designed bytesteam to communicate with the uP? It would check for input and send encoder totals every 10 ms or so; otherwise be sleeping for ISR callbacks.

You might try ROS Serial.  It is aROS node and a library to run on a uP  It lets the uP think it is a real ROS node.  It saves having to re-invent yet another serial protocol.   

Sleep?  You are still thinking UNIX.   The uP likely has no OS.  It's an active loop 

Chris Albertson

unread,
Dec 5, 2016, 8:18:33 PM12/5/16
to hbrob...@googlegroups.com
I have two of these launchpad SBCs and I did not know about the built-in quadrature encoder hardware.

How many encoders can each board handle?  Is there a maximum rate it can handle and What does it look like fro the software side.

Maybe just tell me where to read, 

I have to admit that I pretty much gave up in TI's Eclipse based IDE as it is badly broken on Mac OS.

But the board work well enough under Energia.   Energia is there Arduino based IDE.  It makes it ver easy to port Arduino sketches to the Launchpad.   



To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+unsubscribe@googlegroups.com.

To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+unsubscribe@googlegroups.com.

To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.

jsam...@pobox.com

unread,
Dec 5, 2016, 8:22:31 PM12/5/16
to hbrob...@googlegroups.com

That is the board that I plan to use. I got as far as initializing one quadrature decode and printing the 32 bit position value. Then I got distracted. I started with the Energia development system, which is an Arduino compatible IDE. I haven't decided if I should continue that way or switch to Code Composer Studio.

I'll go back to porting my XMega controller to the TM4C123G board and see how far I get...

- Jeff Sampson

jsam...@pobox.com

unread,
Dec 5, 2016, 8:34:54 PM12/5/16
to hbrob...@googlegroups.com

Mkae sure you have the 123 and not the 120. The 120 didn't have quadrature or PWM.

It has two quadrature channels and they probably run at least 2Mhz input. (I didn't look it up.)

Here is a library if you are running the TI development:
https://github.com/energia/Energia/blob/master/hardware/lm4f/cores/lm4f/driverlib/qei.c

Here is my hacked code for Energia. There was something funny about sharing the NMI pin. This gets around that:

#include "inc/hw_gpio.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"

#include "driverlib/gpio.h"
#define PART_TM4C123GH6PM
#include "driverlib/pin_map.h"
#include "driverlib/qei.h"
#include "driverlib/sysctl.h"

void config_QEI()
{
// Enable QEI Peripherals
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_QEI0);

    //Unlock GPIOD7 - Like PF0 its used for NMI - Without this step it doesn't work
    HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = GPIO_LOCK_KEY; //In Tiva include this is the same as "_DD" in older versions (0x4C4F434B)
    HWREG(GPIO_PORTD_BASE + GPIO_O_CR) |= 0x80;
    HWREG(GPIO_PORTD_BASE + GPIO_O_LOCK) = 0;

    //Set Pins to be PHA0 and PHB0
    GPIOPinConfigure(GPIO_PD6_PHA0);
    GPIOPinConfigure(GPIO_PD7_PHB0);

    //Set GPIO pins for QEI. PhA0 -> PD6, PhB0 ->PD7. I believe this sets the pull up and makes them inputs
    GPIOPinTypeQEI(GPIO_PORTD_BASE, GPIO_PIN_6 |  GPIO_PIN_7);

    //DISable peripheral and int before configuration
    QEIDisable(QEI0_BASE);
    QEIIntDisable(QEI0_BASE,QEI_INTERROR | QEI_INTDIR | QEI_INTTIMER | QEI_INTINDEX);

    // Configure quadrature encoder, use a top limit of 2^32
    QEIConfigure(QEI0_BASE, (QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_NO_RESET | QEI_CONFIG_QUADRATURE | QEI_CONFIG_NO_SWAP), 0xffffffff);

    // Enable the quadrature encoder.
    QEIEnable(QEI0_BASE);
}

void setup()
{
  config_QEI();
  Serial.begin(9600);
  Serial.println("Start:");
  Serial.println("--------");
}

void loop()
{
  int32_t position;
 
  position = QEIPositionGet(QEI0_BASE);
 
  Serial.println(position);
  delay(100);

Bob Smith

unread,
Dec 5, 2016, 8:45:28 PM12/5/16
to hbrob...@googlegroups.com
On 12/05/2016 04:19 PM, Tom Bertalan wrote:
> Not sure which "select" function you mean.
select() or poll() are system routines that let you
watch for events on multiple open file descriptors.
GPIO interrupt-on-change is described in the kernel
documentation. They did a nice job on this doc.
https://www.kernel.org/doc/Documentation/gpio/sysfs.txt


> Which driver are you tweaking?
I think it is bcm_kona_gpio_irq_handler() in the
file .../drivers/gpio/gpio-bcm-kona.c, but I could
be wrong on this. It would be messy to add timestamps
to the sysfs entries so I was thinking of making them
events that are visible on a netlink socket. I've
not gotten too far on this project.

Bob

Patrick Goebel

unread,
Dec 5, 2016, 8:48:34 PM12/5/16
to hbrob...@googlegroups.com

Great discussion!  I can say that I have used the ros_arduino_bridge package for a few years now with good results.  The master branch now includes support for the 3-axis Robogaia encoder shield which is what I use on a couple of robots, one with an Arduino Uno and the 3-axis encoder shield and one with a Mega and the older 2-axis encoder shield.  If you look at the documentation on Github you'll see that others have added support for connecting encoders directly to an Arduino Uno without a shield though I haven't tried that myself.

The PID loop is run on the Arduino.

BTW, the ros_arduino_bridge package also has support for analog and digital sensors as well as PWM servos.  Rather than running as a ROS client node like rosserial, ros_arduino_bridge treats the microcontroller as a slave device and the host PC polls it at a chosen frequency to get the latest values from sensors and encoders.  These values are then published as ROS topics and, in the case of odometry, as a transform between the odom frame and the base_link frame. 

--patrick

-- 
The Pi Robot Project
http://www.pirobot.org/wordpress

Chris Albertson

unread,
Dec 6, 2016, 12:39:37 AM12/6/16
to hbrob...@googlegroups.com
If you are trying to control the speed of a motor you really want the
PID controller as close to the motor as can be. By this I mean the
information the PID is working with should not be "old". If the data
goes through an interrupt handler then some kind of interprocess
communication like sockets, now what you have is a PID making a
decision about how to adjust the PWM duty ratio based in information
about the wheel speed a few milliseconds ago.

Another issue I had with period based speed control was that the PID
loop has to run at a not-constant rate. Noramlle your PID loop runs
at 10Hz or 20Hz and makes a decision based on how many "ticks" are
counted in the 0.1 or 0.05 seconds but with period based speed you
have to make a deices at whatever the period is which can are very
long if the motor is running slow. You "P" term now must be
multiplied by the period and you need to interpolate a lot. How to
do a speed ramp when you sample at irregular intervals. Also you
really have to make sure your clock resolution is a LOT smaller than
the encoder tick rate of you have quantization noise on the velocity
measurement. I tried it. I'm told period based speed can work.
My first attempt rover have the encoders mounted on the wheels and I
wa forced into period based. I think wheel mounted encoders work OK
for odometry but not so good for PID based speed control. I ened
up basically running the motor open loop. I computed calibration
data using odometry and the clock then had a table for PWM v. speed
and just ran open loop


On another topic: If interrupts really are taking 0.03 seconds how
is the rover even working at all with pulses coming at 3,000 per
second? My theory now is the nav stack must have a Kalman filter and
the computed covariance matrix has the odomtry input in effect being
ignored. Finding the odometry data is not correlating to location and
placing a zero in the matrix. You can test my theory by puling the
plug of the physical encoder and seeing if the rover does better or
worse.
> --
> You received this message because you are subscribed to the Google Groups
> "HomeBrew Robotics Club" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to hbrobotics+...@googlegroups.com.
> To post to this group, send email to hbrob...@googlegroups.com.
> Visit this group at https://groups.google.com/group/hbrobotics.
> For more options, visit https://groups.google.com/d/optout.



Bob Smith

unread,
Dec 6, 2016, 12:59:25 AM12/6/16
to hbrob...@googlegroups.com
Chris Albertson wrote:
> based in information
> about the wheel speed a few milliseconds ago.

My direct experience was a lag of 10 to 20 microseconds.
DO NOT underestimate a quad core A8 running at 1.2 GHz.
That said, yeah, I can see your point.


> Another issue I had with period based speed control was that the PID
> loop has to run at a not-constant rate.

First, this is not really a requirement. True, the reporting
interval is not fixed but if it is much faster than the PID
loop everything should work the same. All you need is the
period of the last two edges to get a period and speed estimate.
Second, we want to update the motor control when we have new
information about its speed. I wouldn't trust the D term but
the P and I terms don't really require a constant update rate
do they? I know this is crazy talk on HBRC but as long as it
is a sane (10ms to 50ms) rate, it might not matter.


> How to do a speed ramp when you sample at irregular intervals.

Look at the speed and time and adjust the power. It has to be
"fast enough" but equally spaced updates might not be needed.


> I tried it. My first attempt rover have the encoders mounted
> on the wheels and I wa forced into period based.

Yeah, whether period or frequency based you need ticks fast
enough to get a speed estimate. At slow speed, wheel encoders
might not be able to do this.



> On another topic: If interrupts really are taking 0.03 seconds how
> is the rover even working at all with pulses coming at 3,000 per
> second?

This is for the OP.


thanks
Bob Smith

Tom Bertalan

unread,
Dec 6, 2016, 9:03:08 AM12/6/16
to hbrob...@googlegroups.com

Bob and Chris again,

> All you need is the period of the last two edges to get a period and speed estimate.

So, I suppose using average speed as the number of ticks elapsed divided by the PID period would unnecessarily low-pass the true speed data (though this might actually be desirable). Does this mean I need to check the time at every interrupt?

> whether period or frequency based

I don't know the terminology here. Is the first where you check the time at every interrupt, potentially causing trouble when motors are stopped or barely creeping? And the second is where you divide elapsed ticks by elapsed time in a slower loop?

>> On another topic:   If interrupts really are taking 0.03 seconds how
>> is the rover even working at all with pulses coming at 3,000 per
>> second?

I didn't get a chance to time this evening. Had to watch the season premiere of Westworld with some friends. 😀 But I have hope, justified by my reasonable-looking odometry paths (coming directly from my own code, not gmapping), that my earlier timing was wrong. Watch this space.


--
You received this message because you are subscribed to a topic in the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/hbrobotics/fdwI0QruEMI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to hbrobotics+...@googlegroups.com.

jsam...@pobox.com

unread,
Dec 6, 2016, 9:03:08 AM12/6/16
to hbrob...@googlegroups.com
After I posted that I noticed the link says Energia. So maybe that would
drop right in to Energia. But keep that NMI problem in mind if it
doesn't work on the first channel.

- Jeff Sampson

Tom Bertalan

unread,
Dec 6, 2016, 9:03:09 AM12/6/16
to hbrob...@googlegroups.com
Wow, this thread has gotten lively. Ralph, I bought the TM4C123G. From Digikey, since I couldn't get TI's site to actually add it to my cart.

Patrick, ros_arduino_bridge actually looks really nice. I read about it a few months ago and wrote it off as a crutch for motherboards without GPIO of their own, like a mini-itx/i7 build, but not as much for an RPI. I didn't realize that it was doing nontrivial computations of its own, including locally-PID'd differential drive. And as a bonus I can use it temporarily to get my Adafruit 9dof back into use while learning how to use i2c on the RPI, and just how the 9dof sends messages.

Though, if I use a non-Arduino mcu for encoders, I'll probably use rosserial instead.

Chris and Bob, it does sound like any PID speed control I do should happen on the same device which is counting odometry, whether that's an Arduino, Launchpad, Mbed, or RPi. I'll accumulate ticks by interrupt, then do PID in a slower loop which counts its own elapsed time and the number of intervening ticks to get average velocity per its every loop.

Alan Marconett

unread,
Dec 6, 2016, 11:39:19 AM12/6/16
to hbrob...@googlegroups.com
Some of the PIC (32?) chips have a dual encoder input, the code could do
all of that.

Alan

Tom Bertalan

unread,
Dec 6, 2016, 11:56:19 AM12/6/16
to hbrob...@googlegroups.com
I realized (duh) I was actually just measuring the period between ticks in my previous glibly-reported ISR timing, which obviously is speed-dependent. I did this instead (not great, but at least it's measuring the right thing):
    def interruptCallback(self, data):
        lastt = time.time()
        aNow, bNow = GPIO.input(self.wavePins[0]), GPIO.input(self.wavePins[1])
        if aNow == bNow:
            direc = self.reverser
        else:
            direc = -self.reverser
        self.pos += direc
        
        now = time.time()
        self.elapsed = now - lastt


I then did 
rospy.logwarn('%s: %s sec elapsed on last tick', enc, enc.elapsed)
in my odometry spin function (running at 10 Hz), and got numbers between 6e-6 and 1e-5. Much better.


--
You received this message because you are subscribed to a topic in the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/hbrobotics/fdwI0QruEMI/unsubscribe.
To unsubscribe from this group and all its topics, send an email to hbrobotics+...@googlegroups.com.

Chris Albertson

unread,
Dec 7, 2016, 1:09:34 PM12/7/16
to hbrob...@googlegroups.com
No, that is just a wrong as the first attempt. You are not measuring
most of what is going on. What you are measuring mostly is the time
to do the time() system call.
What takes most of the time is just getting from the electrical pulse
to the first line of code after "def interreptcalback()"

Try this: Write an interrupt driver that counts ticks and every 10 or
100 seconds print the number of ticks to the screen using a foreground
"user land" task. Then connect a function generator to the interrupt
line and notice that the printed number goes up if you adjust the
frequency up. At some frequency this stops. Now you have the
maximum interrupt frequency

The trouble is that as this maximum the computer is doing nothing
other than servicing interrupts and nothing else would run so in
practice you like to use only about 1/10 of that so that 90% of the
process is available for normal tasks
> You received this message because you are subscribed to the Google Groups
> "HomeBrew Robotics Club" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to hbrobotics+...@googlegroups.com.
> To post to this group, send email to hbrob...@googlegroups.com.
> Visit this group at https://groups.google.com/group/hbrobotics.
> For more options, visit https://groups.google.com/d/optout.



Tom Bertalan

unread,
Dec 11, 2016, 1:19:36 AM12/11/16
to hbrob...@googlegroups.com
Chris,

Sorry for the long silence. To update:

Your suggestion is good, but unfortunately I don't have a function generator. Instead, I wrote this sketch to run on an Arduino Mega. It attempts to bit-bang at 1, 2, 10, 100, 1000, 5000, 10000, and 20000 Hz for 2 seconds each. I'm not sure how well it actually achieves this. My first thought was to alter the PWM frequency, but apparently this would break the built-in delay function, which I need to play the PWM for 2 seconds.

I modified my encoder ISR to only step forward regardless of pin states, reconnected its interrupt pin to pin 12 of the arduino, and created the following plot with this script (and this launch file).
data.npz.png

In red are the expected observed frequencies, if everything worked as designed (modulo some change in which t=0). In black are the actual. I suspect that the arduino sketch is not doing its job quite right--I'd need to check this with an oscilloscope (which I don't have), or maybe just a logic analyzer (of which I have the very cheap Saleae one). However I think this at least suggests that interrupts at nearly 10 kHz are possible. At the fairly pathetic top speed of about half a meter per second of which my motors seem capable, and at quarter-resolution, I should be seeing something like 3,300 ticks per second. Borderline maybe?

Assuming it is, I read through the ros_arduino_bridge firmware and the associated pololu motor board library. I think it should be pretty easy to make something with a similar interface for my dagu 5 motor board, and run that on the Arduino Mega. I'll be trying this next. The sticking point is always mucking about with the arduino build process.

Tom

Chris Albertson

unread,
Dec 11, 2016, 1:56:51 AM12/11/16
to hbrob...@googlegroups.com
With Arduino library there is tone(freq,duration) 
The duration is in milliseconds.
So to output a 1 KHz tone for 2 seconds the call is "tone(1000, 2000)"
It writes a square wave to a digital pin.

You are getting believable results now


--
You received this message because you are subscribed to the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+unsubscribe@googlegroups.com.

To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.

Tom Bertalan

unread,
Dec 11, 2016, 11:24:49 AM12/11/16
to hbrob...@googlegroups.com
Chris,

I used tone, and a slower sampling rate, and got better results. 
data.npz.png
Not sure what that tiny intermediate flat/steep step is about.

I still think I'll be trying ros_arduino_bridge, though, for PID control and for easy access to my adafruit 9dof.

Tom Bertalan

unread,
Dec 13, 2016, 1:42:19 AM12/13/16
to hbrob...@googlegroups.com
Patrick, I've started using ros_arduino_bridge this evening. It's some pretty fancy code!

Do you have any suggestions for me on where I could go for troubleshooting advice on using the ros_arduino_bridge with directly-connected encoders? I know you said you went the robogaia route, but I'm going to list my symptoms here in the hopes someone has a suggestion, or at least so I can later copy them to a different forum.

I modified the #define's in this commit, concatenated all the ino files into one (so I can use Arduino.mk), and made a version of the fairly simple pololu motor driver library for my board. I think I connected correctly my motors (direction on 7 and 8; PWM on 9 and 10) and encoders (left on 3 and 4; right on A4 and A5), but I'm having the problems that
  1. The odom topic doesn't show any encoder activity, or simply sending the `e` command directly in the serial monitor always returns `0 0`. I verified with a logic analyzer that I am in fact getting the right square waves out of the four encoder pins.
  2. When I give motor speed commands (either through teleop_twist_keyboard.py or the `m` command in the serial monitor), only my left motor turns, and only for a moment. I suspect this problem will be change or disappear when I fixed the first one.
Thanks in advance for any ideas you might have!

Patrick Goebel

unread,
Dec 13, 2016, 11:18:25 AM12/13/16
to hbrob...@googlegroups.com
Hi Tom,

Glad to hear you're giving ros_arduino_bridge (RAB) a try.  Here are some thoughts regarding your situation.
  • I haven't tried the direct encoder connection myself but there is a potentially relevant thread on Github that might be worth checking out.

  • You might have already done this, but if the Dagu motor driver comes with its own test sketch, make sure you are getting both left and right motor control using that sketch.  Alternatively, write your own simple sketch and call the left and right motor control functions to make sure everything is working at the driver level.

  • Ditto for the encoders.  Perhaps you already have some code that enables you to read the encoder counts when you passively move the wheels/motor shafts?

  • When issuing the 'm' command, the RAB firmware automatically stops the motors after 2 seconds as a safety precaution.  When publishing Twist commands in ROS, these need to be published continually to keep the robot moving.

This morning I wired up a new Arduino Uno clone with an Adafruit motor controller V2.3 and the Robogaia 3-axis encoder shield.  I then tested the latest master branch RAB code and it appears to work fine.  HOWEVER, at one point I also ran into the problem of only one motor turning.  In my case it was caused by a poor connection on one of the motor terminals--it looked OK, but when I removed the lead and reconnected it, things started working again.

--patrick

-- 
The Pi Robot Project
http://www.pirobot.org/wordpress

Tom Bertalan

unread,
Dec 17, 2016, 10:32:29 PM12/17/16
to hbrob...@googlegroups.com
Patrick,

Let me preface this by saying that I've tried running this code on an Arduino Uno, and it works there. So this somewhat diminishes the urgency of the problem to one academic. But I'd still like to understand what's going on, with the possible utility of being able to switch to a less breadboard-y board, like a pro mini, in the future.

I spent several hours today trying to get RAB working with my hardware. I'm not too concerned about getting the motor control half working--it's just a PWM for speed an a digital write for direction, which I've abstracted out easily enough into some code which implements the same interface as the Pololu driver.

Interrupts for encoders are more of a problem. It seems that the RAB code is written for an Arduino Uno, for which (e.g.) port D, pin 2 equates to silkscreen pin 2, as per the comments in encoder_driver.h, and Appendix A of this pdf. However, I'm trying to get this to work with an Arduino Mega 2560. There, the PD2/PD3/PC4/PC5 used by default in encoder_driver.h map to 19/18/A12/A13 respectively, per both https://goo.gl/DvHEUA and https://goo.gl/xAwBGM.

My concern is that, while I can simply wire my encoders to pins 19...A13, these might actually not correspond to PCINT2_vect and PCINT1_vect, as used in encoder_driver.ino However, I haven't been able to find a good reference on which interrupt vectors I should actually be using for the mega2560, and, relatedly, which PCMSK* and PCIE* I should use.

Additionally, I have some confusion about the way the actual ISRs are written:

  static const int8_t ENC_STATES [] = {0,1,-1,0,-1,0,0,1,1,0,0,-1,0,-1,1,0};  //encoder lookup table

[[snip]]

  ISR (PCINT2_vect){
  static uint8_t enc_last=0;
enc_last <<=2; //shift previous state two places
enc_last |= (PIND & (3 << 2)) >> 2; //read the current state into lowest 2 bits
   left_enc_pos += ENC_STATES[(enc_last & 0x0f)];
  }

Does the line  enc_last <<=2;   actually have any effect?? enc_last is initialized to zero every call, right? For that matter, how is it able to store any state between ISR calls? I mean, I guess it does work, on the Uno, but I don't understand how. Is this some magic with the ISR macro? Do you know how I might get in contact with James Nugen, to ask about these things?

As you suggested, I did ensure that I was able to read the encoders with my own vanilla attachInterrupt code, and that worked fine (commits f56f56 and b124e4 in my repo). If I can't get the fancy port-reading version of RAB to work, I might just replace those parts of the code with my own external-interrupt/attachInterrupt-based code. Or, more likely, just use an Uno, and forget about it.

Tom

Chris Albertson

unread,
Dec 18, 2016, 12:51:32 AM12/18/16
to hbrob...@googlegroups.com
First off, I can't see how your encoder handler can work.  There seems to be no memory.  A quadrature encoder needs to somehow remember the previous state.  Your "enc_last" is inside the scope of the ISR.  Maybe all you need to do is move the definition two lines up so it becomes "file scope" or "global" and does not get re-initialized each time.     I did not look any farther.  Can't know if it will work because I don't know what triggers the ISR, raise, fall or change

I have seen these lookup based quadrature handlers before but I wonder if they are faster than the normal kind that use a bunch of nested if statements?

On another subject: 

I just found out about these $3 ARM boards.   http://www.ebay.com/itm/STM32F103C8T6-ARM-STM32

About the size and cost of an Arduino mini clone but it is 32-bits, runs at 72 MHZ, 64MB flash, 20K RAM and has more usable pins.  Also som one wrote an Arduino boot loader for it so if you like you can use Arduino IDE and the sketches will run.   I've also gotten mbed IDE to work with it so I can run a full-on RTOS.    I'd not bother with using a Mega, these are better and 10% of the size and cost.   OK the catch is ARM is always 3 volts not 5 so maybe some level shifting.

My goal is to have the uP (This ARM, Arduino or whatever) be powerful enough to run a PID speed controller on a four week drive rover and also run some simple test behaviors like "drive a 1 meter square", or "drive forward until you detect a obstacle then turn around" all without ROS or the Pi3 even powered up..  ROS will run on a Pi3 but I want to be able to test the rover's drive and power systems without something so complex as a Linux/ROS machine


--
You received this message because you are subscribed to the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+unsubscribe@googlegroups.com.
To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.

Tom Bertalan

unread,
Dec 18, 2016, 7:44:09 PM12/18/16
to hbrob...@googlegroups.com

Chris,

Yes, that stood out to me as well. I briefly tried it both ways, and I think the encoder actually incremented the correct direction both times, though much faster with the declarations inside the ISRs. I'll need to do some more careful testing, as well as just read the code more carefully. I'm new to the bitwise math.

I tried to use RAB for odometry and motor control this morning while gmapping and running the path planning stack, but it didn't seem to be working. My suspicion is that the LIDAR, arduino, and WIFI dongle weren't coexisting well on the USB bus.

Tom


To unsubscribe from this group and stop receiving emails from it, send an email to hbrobotics+...@googlegroups.com.

To post to this group, send email to hbrob...@googlegroups.com.
Visit this group at https://groups.google.com/group/hbrobotics.
For more options, visit https://groups.google.com/d/optout.

--

Chris Albertson
Redondo Beach, California

--
You received this message because you are subscribed to a topic in the Google Groups "HomeBrew Robotics Club" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/hbrobotics/fdwI0QruEMI/unsubscribe.

To unsubscribe from this group and all its topics, send an email to hbrobotics+...@googlegroups.com.

jsam...@pobox.com

unread,
Dec 19, 2016, 12:13:29 AM12/19/16
to hbrob...@googlegroups.com
Tom,

Did you get the TM4C123G board that you ordered?

I got my controller code to run on the TM4C123G Launchpad board. Then,
out of curiosity, I converted ros_arduino_bridge to run on the TM4C123G.
It isn't cleaned up as well as it should be, but it appears to work. And
I didn't test any of the "extra" functions, just the motor control.

If you are interested in trying it I can send you the changes.

But the catch is, you have to download and run Energia 18 to compile it.
The baud rate has to be set to 9600 (the baud rate on the debug
interface defaults to that). I added a #define to output PWM and
direction instead of forward PWM and reverse PWM but I can't guarantee
that works. But it does run my motors using my forward PWM and reverse PWM.

Oh, an added advantage, the GPIOs (most of them) are 5 volt tolerant.
And you can directly connect 5 volt encoders to the Launchpad board
without level translation.

- Jeff Sampson


Tom Bertalan

unread,
Dec 19, 2016, 12:38:47 PM12/19/16
to hbrob...@googlegroups.com
Jeff,

I did get it, yes. I'll be traveling for the next week though, so unable to do any proper testing. But I could at least get my compilation environment working. Were you able to use CCS to program it? I use Eclipse for all my day-to-day work, so I thought that would be nice. But running the debug target just gives me "Error connecting to the target: Frequency is out of range.", and running the release target gives me "cannot open source file "inc/hw_nvic.h""

TBH, I'd prefer a simple makefile-based solution for compiling and uploading, but I get a "Unable to find any ICDI devices" when I go that route. I suspect my first and third problems share a common root cause. I'll bring my EK-TM4C123GXL with me on my trip and see if I can get it working with my a laptop, though I suspect I'll be busy with other work when I have time use my laptop at all.

Tom

jsam...@pobox.com

unread,
Dec 19, 2016, 12:38:55 PM12/19/16
to hbrob...@googlegroups.com
I just noticed that TI has at least two boards that they call TM4C123G.

I have the $13 board:

http://www.ti.com/tool/EK-TM4C123GXL

And not the $149 board:

http://www.ti.com/lit/ug/spmu357b/spmu357b.pdf

Apparently the big board is called a development board. The small board
is called a Launchpad board.

My code runs on the small cheap $13 EK-TM4C123GXL Launchpad.

Sorry if I caused any confusion.

- Jeff Sampson

jsam...@pobox.com

unread,
Dec 19, 2016, 9:53:32 PM12/19/16
to hbrob...@googlegroups.com

Well no, since ros_arduino_bridge was written for Arduino, it made sense to compile it under an Arduino-like environment. So I used Energia which is designed for the TI boards.

I didn't try anything under CCS, because I couldn't get any of the download links to work. But I just now did another search and found CCS7 for Linux. I will see if that installs.

Just casually looking through ros_arduino_bridge it looks like the motor/encoder/PID (at least the way I did the motor and encoder) doesn't use a lot of Arduino functions. But you would have to create your own start up code and supply your own serial and timer functions. My motor and encoder modules should compile under CCS.

But all of the "extra" functions are going to drop right in. (like pin configuration, servo, analog read, ping, etc.)

I'll see if I can get CCS to install. And then I'll get back you...

- Jeff Sampson

jsam...@pobox.com

unread,
Dec 19, 2016, 10:21:03 PM12/19/16
to hbrob...@googlegroups.com
Whoops. This:

> But all of the "extra" functions are going to drop right in.

Should say this:

> But all of the "extra" functions are NOT going to drop right in.

Tom Bertalan

unread,
Dec 20, 2016, 8:10:49 AM12/20/16
to hbrob...@googlegroups.com

Jeff, thanks for your scouting. At the moment, I'm getting pretty good results with just an Arduino, but once I fix the ROS-originating problems detailed below, I think it's pretty likely that I'll return to the 32-bit ucontrollers in the hopes of improving odometry and high-update-rate PID. RAB has given me great success today--read on...

After adding a debug command to RAB's command.h, I was able to notice that my left encoder's wires were connected to my right encoder's pins, and v/v. After fixing that, I get good PID and odometry, though I suppose the wheel/wheel base geometry parameters could perhaps be tuned slightly.

I made some new videos this evening showing move_base results with the new embedded odometry source and PID speed control. It's significantly better than the RPi results were, but the leftward list is still apparent in the first video:
https://youtu.be/La1HR6EwuGI

I found, however, that this bias can be fixed by setting min_vel_theta to the negative of max_vel_theta. I had assume that those were absolute rotational speed limits, but it looks like they're actually signed---I was explicitly disallowing right turns.

However, after fixing that (and also modifying some other parameters with the goal of making movement more slow and deliberative), an underlying problem becomes more clear--the local planner keeps trying to backtrack to the root of the global plan for some reason, like an old man who keeps thinking he forgot something. This sound like just the sort of problem that the prune option is supposed to fix, but that's on by default, and turning it on explicitly didn't help anything.
https://youtu.be/itdsMdsVfCY
https://youtu.be/1LCFzeLqWfs

I've been trying various parameter tweaks on this, but haven't fixed anything. My next focus will be reading the path planning code and perhaps recompiling it with various debug prints, unless something obviously wrong jumps out to any of you about what might be wrong with my path planning. I'm traveling for a week starting tomorrow, but I might still be able to get some testing in remotely, with the help of a local assistant to do battery recharges!

Tom


Tom Bertalan

unread,
Dec 20, 2016, 3:08:18 PM12/20/16
to hbrob...@googlegroups.com

I should also note that I did move the encoder memory declarations to outside the ISRs as Chris and I discussed, and gave them separate names for right and left (though in principle one of the two ISRs could be modified to use the top four bits of enc_last, and the other can continue to use the bottom four bits, I figured I'd leave this optimization til later). I'll look into doing a pull request with lesser change in a couple days here.

I'm writing this on a flight, and I spent the first hour or so of the flight reading a PDF called "ROS Navigation Tuning Guide", by Kaiyu Zheng. This gives a lot better documentation of many of the parameters of the navigation stack than is available on the wiki, though there are still some holes. Notably, It says that:
(1) I can set negative values for the minimum translational (x) velocity, to allow for backing up. Perhaps then at least, when he feels the need to go back to the start of the global plan, he can do so without two 180* rotations (which at the moment are often done not in-place, resulting in lots of lost ground). However, Zheng notes that negative values min_vel_theta are not respected by DWA, without clarifying exactly what min_vel_theta means in that case. Is it the absolute minium speed magnitude (to account for static friction)--a parameter which then is simply not available in DWA alternatives? Does DWA not allow right turns??
(2) When using navfn or global_planner,  I can use cost_factor and neutral_cost to create global plans which use more right-angle turns to avoid taking oblique paths through doorways and openings, by avoiding costmap hotspots. Zheng also gives rules of thumb for tuning inflation radius and cost_scaling_factor for good performance in hallways which I'll try out.

I have some doubts about whether my parameter changes up to this point all were actually taking effect. It's not super clear which ns keyword parameter I should provide when loading my yaml files into launch files, or whether to group parameters under a subsection such as TrajectoryPlannerROS (can't remember the exact name) within the yaml files. My hope is that I can do a launch with my parameter files commented out, then use rqt_reconfigure to get some guidance on where the default values are showing up.

I'll try to test some of these ideas out when I finish flying for today, and get to a place where I can SSH into my robot. I also brought my new cache of 32-bit ucontrollers (tiva c, mbed, and teensy) with me, FWIW. Maybe I'll play with them some as well; likely not.

Tom

Chris Albertson

unread,
Dec 21, 2016, 3:05:44 AM12/21/16
to hbrob...@googlegroups.com
My code runs on the small cheap $13 EK-TM4C123GXL Launchpad.

I have two of those.   TI's Eclipse based IDE is completely broken on Mac OS.  I've been emailing the people at TI and sending them log files and doing experiments.  You'd think TI would just spring for a Mac and not make their customers do al there testing and debugging.    It does work under Energia and I am impressed by the new multi-taking Energia.  It is dead easy to use just like Arduino but gives yo a small RTOS on the  Launchpad.

But also on my desk right now are two $2.39 ARM based boards that are 1/4 the physical size of a launchpad and with about as many pins. (they are the size of  an old 40-pin DP chip.) So far I've figured out how to run them with Arduino IDE, GCC and mbed.   I can't see how they can sell for $2.39

Patrick Goebel

unread,
Dec 22, 2016, 11:00:37 AM12/22/16
to hbrob...@googlegroups.com
Hi Tom,

What happens if you set a goal that is not outside your map area?  In your second and third videos below you set the goal outside your map.

--patrick

Tom Bertalan

unread,
Dec 23, 2016, 10:20:40 PM12/23/16
to hbrob...@googlegroups.com
Patrick,

Thanks for the suggestion. It would be good to establish a set of tests which isolate mapping from navigation, and tests things like unobstructed navigation and navigation around corners separately. I'll check and report back when I get home. At the moment, I can report that the changes to cost_factor and neutral_cost did seem to help with creating a global plan less susceptible to collisions with corners, but testing was difficult over a long-distance low-speed connection.

Tom

Tom Bertalan

unread,
Dec 29, 2016, 1:55:12 AM12/29/16
to hbrob...@googlegroups.com
I increased pdist_scale and gdist_scale, and am now getting much better results--the global plan which my previous changes to neutral_cost and cost_factor caused to nicely avoid corners is now followed more closely.

Previously, corners would be cut:

My remaining problem is that, at the beginning of a trajectory, move_base will sometimes freeze if we're facing into a corner and we're pretty close to the wall (lying largely in the blue obstacle expansion region). If I teleop an in-place turn until we're 90 degrees or less from the planned global path, move_base will take it from there and start moving. This freezing only happens at the start of a trajectory--if I'm careful always to end my trajectories with a pose facing away from the wall, move_base will drive right into the blue zone, then do a final in-place turn with no problem (after which a subsequent new trajectory following will not require an initial teleop).

Unfortunately, it looks like I deleted the video I took of this phenomenon, and I'll be unable to record a new one for a few days while I wait for some replacement motors (a gear lost a tooth). Still, does this sound like a sufficiently familiar situation that anyone is able to offer a suggestion for how to fix it?

I did try setting recovery_behavior_enabled and clearing_rotation_allowed back to true in my move_base_params.yaml, and also
recovery_behaviors: [
  {name: conservative_reset, type: clear_costmap_recovery/ClearCostmapRecovery},
  {name: aggressive_reset, type: clear_costmap_recovery/ClearCostmapRecovery},
  {name: rotate_recovery, type: rotate_recovery/RotateRecovery}
  ]
but the freezing persists (and I didn't see any of these behaviors being performed at other times either).

After I get this behavior fixed, I might try doing some higher-level goal planning (like frontier exploration), and starting to do something interesting with my USB webcams, like object recognition. I also think it might be nice to segment the map into rooms by e.g. a spectral clustering, and then write a simple ui (probably backed by a ros node exposing services) for choosing navigation goals on a per-room basis.

Tom

Patrick Goebel

unread,
Dec 31, 2016, 12:12:48 PM12/31/16
to hbrob...@googlegroups.com
Hi Tom,

I'm looking at your navigation parameters here on Github.  In your file base_local_planner_params.yaml  you have min_vel_x set to -0.10.  As far as I can tell, this parameter has to be 0 or greater (mine is set to 0.05).  If you set it to be negative in your parameter file, it ends up actually be set to 0.0 on the parameter server.  If you then have a heavy robot, setting a value this low may cause it to stall under certain conditions such as at the beginning of a trajectory.

Moving backward is taken care of by the escape_vel parameter which is -0.1 by default.

So try setting min_vel_x to 0.05 to see if that helps.

NOTE: I'm using ROS Indigo from Debians packages on Ubuntu 14.04.

--patrick

Tom Bertalan

unread,
Jan 14, 2017, 11:52:51 PM1/14/17
to hbrob...@googlegroups.com
Patrick,

Sorry for the large delay in examining your advice!

I set to negative because I read somewhere that, like the minimum theta velocities, it should be signed. You may recall that I had Zoolanderesque problems when min_vel_theta was positive. I've changed min_vel_x to 0.05, and the stalling seems to have stopped. I suppose the original problem for this thread is comprehensively solved at this point. I'm not a very experienced forumite; is it etiquette to stop posting to the thread at this point? I'll make it a point to give a more serialized treatment to this project on tomsb.net

Tom


Patrick Goebel

unread,
Jan 17, 2017, 10:16:45 AM1/17/17
to hbrob...@googlegroups.com
Hi Tom,

Glad to hear that might have helped although my experience with move_base parameters is that just when you think you have solved a problem, it comes back a few days later, usually in the middle of a demo in front of a group of dignitaries or VCs...

Great that you are going to post a summary on your website.

--patrick
-- 
The Pi Robot Project
http://www.pirobot.org/wordpress
Reply all
Reply to author
Forward
0 new messages