The “ping pong” approach is fantastic when you build something new. I find it quite hard to use when you change something that’s already in place. It works really well for Unit Tests. For integration tests, you might want to switch pairs as you change layer. Ex: When building a JSON API, you can switch driver when you change controller / model / service / serializer etc.
Changing role every 5 minutes or so work as well. I think it’s important to understand what your role is as a driver and navigator. This gist provides pretty good guidelines.
As you mentioned, pair programming is different when one of the developer is more experienced. The person that’s more experienced gains a lot from having to explain why she suggests to do things a specific way. In my experience, both learn a lot in the process.
I believe that it’s good to not pair-program all the time. There are “creative” explorations that you might want to do on your own without having to justify every line you write. It can also be more efficient to have the engineering team explore and agree on architecture (and naming!) before one developer implements than making all those decisions while pair-programming.