How did USB 2.0 avoid collisions?
USB is strictly master-slave. The device does not transmit unless the host tells it to transmit.
Even so called "interrupt" mode is really polling: for example, every 8 milliseconds (or less if you got a gamer mouse), the PC asks the mouse "what is your position" and the mouse replies.
Same if you have a USB-serial interface for example. When the interface receives data on the serial line, it will not transmit it to the PC. Instead it will wait for the PC to initiate the transaction and ask for the data.
This webpage has a good explanation about the packets that are exchanged. Basically, keep in mind that USB was implemented to allow the dumbest and cheapest possible peripheral to function, which means most of the intelligence is in the host, host usb controller, OS, and drivers. This is very apparent when reading the spec.
Firewire (for example) has a completely different philosophy, it is much more powerful, it's multi-master so devices can talk to each other without help from a host/master. It is actually much closer in its philosophy to something like token ring with isochronous transfers slapped on top, than to USB. However "multi master" means it requires a powerful microcontroller in the devices, running a complex software stack. It is therefore more expensive, and thus limited to expensive products like camcorders and fast hard drive enclosures. A firewire mouse makes no sense, it would be too expensive. That's one of the reasons why FireWire failed.
In USB framework devices can't communicate simultaneously, because they only "talk" when USB host "allows" them to talk. And USB host allows another device to "talk" only when the sequential transaction protocol with the first device is completed. And USB devices don't have any means to "talk" on their own, there is no active interrupt mechanism in the USB. In brief, the mechanism of implementing this discipline is as follows.
After USB 2.0 devices are connected, host enumerates them by assigning unique addresses to each device.
Every transaction on the bus is initiated by USB host.
Headers of every USB transaction carry specific device address. Even when the transactions are broadcasted over the entire USB tree (on the particular host controller instance), only the device with matched address would respond to the transaction, and either take the data, or respond with data.
The link "partners" then will send an acknowledge in the direction from who receives the data successfully. The entire transaction follows established protocol with defined sequence of tokens, time-outs, and error correction codes, to ensure integrity of the transaction.
All other devices are just listening and ignoring the traffic which is not directed to them.
That's about it, it is "half-duplex" interface.