Is there a way to do this using dict.setdefault() ?
Of course! There's nothing magic about setdefault; it just returns my_dict[name] if it exists, or sets my_dict[name] = default and returns default if not.
Either way, what it returns is the (potentially new) dict in my_dict[name], so all you have to do is update it:
my_dict.setdefault(name, {})[id] = pin
Or, if you really like using update instead of just [] =:
my_dict.setdefault(name, {}).update({id: pin})
For example:
>>> my_dict.setdefault('name1', {})['id10']= 'pin10'
>>> my_dict.setdefault('name3', {})['id20']= 'pin20'
{'name1': {'id1': 'pin1', 'id10': 'pin10', 'id2': 'pin2'},
 'name2': {'id3': 'pin3', 'id4': 'pin4'},
 'name3': {'id20': 'pin20'}}
More generally, you could obviously rewrite your existing code to this:
if name not in my_dict:
    my_dict[name] = {}
my_dict[name].update({ id : pin }
Whenever you can do that, you can use setdefault. (But notice that we're calling a mutating method or assigning to a key/index/member of my_dict[name] here, not just assigning a new value to my_dict[name]. That's the key to it being useful.)
Of course almost any time you can use setdefault, you can also use defaultdict (as demonstrated in CoryKramer's answer) (and vice-versa). If you want defaulting behavior all the time, use defaultdict. Only use setdefault if you want defaulting behavior just this once (e.g., you want defaulting while building the dict up, but you want KeyErrors later when using it).