A good start here might be the RRT algorithm (https://en.wikipedia.org/wiki/Rapidly-exploring_random_tree) or one of its many, many variations. Let's assume you're doing this in the configuration space (perhaps the motivation will become clear later on).
How the algorithm works (basically):
- Start with some initial configuration $q_0$, goal configuration $q_d$, and some step size $\Delta$
- Initialize an empty graph $G$
- Pick some random configuration $q_r$
- Create a new configuration $q_n$ such that $q_n = \frac{q_0 - q_r}{|q_0 - q_r|}*\Delta$
- Check to see if $f(q_n)$, where $f(\cdot)$ is your forward kinematics function, results in a collision for any of your robot's links
- Yes? Discard $q_n$
- No? Keep $q_n$ and store the edge $(q_0, q_n)$ in $G$
- Repeat this process using a random $q_i \in V(G)$, where $V(G)$ denotes the vertices of $G$, as the initial starting point and execute until a $q_n$ is found such that $|q_n - q_d| \le \Delta$ (or until some max number of iterations have concluded)
The solution given by the algorithm is then the shortest path from $q_0$ to $q_d$. More recent modifications to the algorithm do a much better job at being sample efficient as well. Furthermore, keep in mind that collisions will be easier to calculate if you have the actuator configuration already, as opposed to computing it via the inverse kinematics function. However, if the number of actuators your robot has is $\gg 6$, it could end up being more efficient to sample in the workspace and perform inverse kinematics as necessary.