MarIOnette Tutorial: Make Your Own Post-It Drawing Robot
HTML-код
- Опубликовано: 14 июл 2024
- Thanks for watching!
Link to project: github.com/knee-koh/MarIOnette
Link to files and hardware to purchase: github.com/knee-koh/MarIOnett...
Blender - www.blender.org/download/
Arduino - www.arduino.cc/en/software
Chapters:
00:00 - Introduction
00:12 - Overview of Steps
00:27 - Installing Blender
00:37 - Getting the Plugin From Github
01:01 - Installing MarIOnette on Mac
01:29 - Installing MarIOnette on Windows
01:36 - Installing MarIOnette on Windows (For Real This Time)
02:07 - Installing Arduino
02:20 - Installing Libraries
02:37 - STL Files
02:41 - Print Settings
02:51 - Blender Rigging Tutorial
03:04 - Importing Geometry
03:14 - Scale Geometry and Apply Scale
03:55 - Splitting Mesh
04:24 - Organizing Objects
04:36 - Merging Common Objects Together
05:47 - Creating Armature
07:11 - Creating Arm Bones
12:30 - Symmetrize Bones
13:39 - IK Bone
14:16 - Linking Objects to Bones
16:23 - Locking Axes of Rotation
17:55 - Adding IK Constraints
19:11 - Locking IK Axes
21:13 - Creating IK/FK Switch Bone
21:54 - Limiting Location of Bone
23:22 - Creating Driver to Control IK Influence
24:52 - Creating Custom Bone Shape
29:06 - Creating Background and Hiding Guides
30:50 - Required Hardware
30:56 - Threaded Parts
31:32 - Installing Servo Horns
31:39 - Large Bearing Installation
31:44 - Servo Installation
31:55 - Attaching the Face
32:08 - Small Bearing Installation
32:20 - Attaching Arms to Servo Horns
32:38 - Assembling Lower Arms
32:52 - Attaching Pen Holder to Lower Arms
33:01 - Attaching Lower Arms to Upper Arms
33:15 - Installing Pencil
33:23 - Arduino Wiring
33:43 - Syncing MarIOnette to Arduino
34:19 - Uploading Code to Arduino
34:38 - Connecting to Arduino
34:48 - Linking Servos to Bones With MarIOnette
35:59 - Setup Done
36:09 - Follow Path
I could hug this man rn...
Same
Wow, this is a game-changer! I really need to get into this stuff. Basically no coding, just a blender. I'm amazed.
Excellent work! Thank you so much for sharing!
This is great. Can't wait to see more.
this is awesome ! will be trying this out !
i love you for making this, thank you!
Excellent work
thank you for sharing
great work!thanks!
great job brother
Damn! thank you for sharing, have a grateful day ❤🔥❤🔥❤🔥
Wooooow! Please do more tuts!
game changer!
This is simply amazing. Thanks you.
Wow this is amazing great video..Ive been working on programming exactly this... I have an old video uploaded showing servos and blender communication and My next step from servos was to do stepper motors for a big 6 axis robotic arm or even multi axis cnc control...i would love to work on the development of this with you if at all interested
I have been waiting years for something like this! Well done! I have an issue when downloading the obj from Git. I get a list of vertices (I think) rather than a 3D file. All the STLs downloaded fine but the OBJ is just a list of numbers. I'm new to Blender and Git but not to building Animatronics. Apologies if this is very silly newbie mistake
That looks like a weird quirk with Github... You can download the entire repo (go to the main MarIOnette github page and then click Code > Download ZIP). Then unzip the file on your computer and you should be able to open the file.
An alternative to avoid having to download the entire repo: here's the raw file path (raw.githubusercontent.com/knee-koh/MarIOnette/main/Examples/Drawing%20Robot/OBJ%20File/Post%20It%20Drawer%20V3.obj). Just use your browser to save this file (save or save as, and specify a .obj extension).
I'll update the next release to have the .obj file be in a .zip so it's easier to download
@@knee-koh Thanks very much for the reply. In the end I copied and pasted the text into a text editor and saved it as a .obj. I have managed to work my way through the entire tutorial (with a few stumbling blocks). Adding the PWM library (that you mention in the github doc but possibly not in the video?) and changing the baud rate to 115200 got it working for me. I really can't thank you enough for developing this plug in and I'm anxiously awaiting your next tutorial. You have made a wonderful tool. Well done!
cool!!
this look awesome. do you think you could make this work with GRBL/would it be possible to have it output g-code and not be installed on the arduino
Rigging gives you an appreciation for URDF files especially since they accept Stl meshes too. Would this be able to accept gcode instruction?
Could this be done with a state machine, FreeRTOS, with many servos different directions, and different timing and delays. I would like to see maybe rather we add Daz Studio stuff to it like our Daz Studio chatbot or just Daz Studio plugins and artworks in general. Then, that would be awesome. We would just need computer vision capable plugin and accelerometers or gyroscopes in the microcontrollers. If it could be based on the stm32 cortex core instead of just the atmega328 in the arduino.
Great addon and amazing tutotorial. Quick question is it possible to do the reverse. In that can I physical move the robot and let blender track siad movement and be able to move the 3d model?
Yes, I am currently developing that feature: github.com/knee-koh/MarIOnette/blob/main/Media/Gifs/ElmoInput1.gif
An important note: you will not be able to do this with off-the-shelf RC servos like the one in this project. The Arduino needs to be able to get the rotation angle from the servos, so something like a Dynamixel or LX-16A will be required (or you will have to modify an RC servo and solder wires to the potentiometer in order to get the angle).
@@knee-koh ok great. What I will like to use it to make a robot arm or floating stylus and use that to probe around a part for a car and get a point cloud or 3d geometry and then let the industrial size arm cnc machine the part at a different scale
This is really great stuff. I completed this post-it bot tutorial successfully. had a bit of a time getting Arduino to write to the nano but once that was figured out, everything worked perfectly.
I was curious if there's a solution to save an animation loop or even a set of animations stored on the Nano, or perhaps a USB drive for it to operate independently from blender. like, if I want to activate an animation out in the field, not connected to a computer, by just pressing a corresponding button on a box, so to speak. I'm a novice to this kind of stuff so if this question isn't clear, it's likely that I don't exactly know the appropriate language to describe what I'm asking.
I saw that my questions are answered in another video. 🤦🏻♂
I've been able to get this to work with an Adafruit Feather M0, but now I'm attempting to use an 8-Channel Featherwing PWM and I'm running into a wall getting it to interact with blender/marionette. Any recommendations or resources that could help me through this?
@@benploughman4145 , sorry for the late reply! I saw your comment on another video about SD card/localized animation playback; hopefully my answer explained that process a little better (though I am working on another tutorial that will walk through the process more thoroughly).
Happy to hear it works on an M0! In terms of getting it to run on the 8-channel Featherwing board, you'd need to write some code to handle communication with that specific chip. Fortunately Adafruit has taken most of the hard work with their libraries, so you'd need to do the following:
- Create servos and attach motors inside MarIOnette as if they were attached directly to the board
- Sync the files to create the .ino and .h files for your project
- Uncheck "Overwrite Arduino File" so you can edit the files freely in case you need to re-generate more code
- In the generated .h file (the one MarIOnette uses), you'll have to include the Featherwing libraries and connect with the board (use Adafruit's examples to see how to do this and copy over the code)
- From there, you just need to replace any Servo.write() or Servo.writeMicroseconds() lines of code in the .h file with the corresponding Featherwing commands. That way, your microcontroller will tell the Featherwing to actuate the servos over the i2c bus instead of the native PWM pins
Hello everyone. Does anyone know where in Europe I can buy a larger bearing from the video above. I am asking about a bearing with dimensions of 26mm x 20mm and a thickness of 4mm
could this be done on a pico using micrpython?
how can I record motion or an animation in blender and save it to the nano/micro controller so that I can make it do that without the computer, for example when friggered by a button linked to the board?
Hi, I have a tutorial mostly edited covering lots of new features including close to what you're asking. Until it's posted (lots of things keeping me busy at my day job, sorry!) you can follow these steps: the 1.0.3 and 1.0.4 builds of MarIOnette supports saving an animation to a file and playing it back from an SD card.
- Cache the file in the in the Cache menu (make sure to check "Write cache header file")
- Transfer to an SD card
- Trigger it in the Arduino code. The latest .ino Arduino file in the github has some commented code on lines 167-177 that shows an example of how to load in an animation. You can trigger that code with a button press/other input.
Unfortunately it will be some time before animations can be uploaded directly to the microcontroller, since there are so many boards with varying memory sizes floating around. Once my other work calms down a bit I'll look into tackling that and other requested features.
@@knee-koh thank you. I will check the latest build. In terms of boards, I think a good one to add support for would be the PCA9685. It supports 16 servos and you can chain up to 62 of them together. Thanks for making this! It’s awesome.
Exciting to hear you cooking more tutorials
Hey man, amazing work. Really.
When i was a kid, I kinda liked coding animations. I felt oddly powerful, but now, as I've grown, my projects grew too, and it's too frustrating to keep iterating in small adjustments etc etc.
Anyway, I'm finding difficult to control steppers. I'm using a RAMPS 1.4 to control a 5 axis robot camera slider. Everything is connected properly, and with a test code all the motors run properly.
I copied the same dir and step pins in MarIOnette, connected all the bones (selecting show value confirms the correct bones are linked). No problem uploading code and connecting (the serial becomes busy) but nothing moves. controlled config.h and found the first value of all motor's array was 5 (the same number of motors), guessed maybe a little bug on the less used steppers config generator didn't set the correct index, but nothing. Any suggestion? thanks in advance
P.S. I'm planning on releasing a video about the project and the project itself (when it will be i a releasable state)
Okay, quick update: specifing the driver's enable pins and putting them low made the axis lock while not connected which seems intended behavior (except for one, which keeps moving very very slowly an jittery in one direction).
Connecting to MarIOnette while an animation plays makes all the axis release. Stopping the animation makes the axis locks after a few seconds and resuming the animation doesen't release, and all axys stay locked. Same happens if connect whithout an animation playing. P.s. Tried to change the first element of each motor array back to 5 (in config.h) but nothing (changing them to 0, 1, 2, 3, 4 changed the stepper which slowly turns while not connected, so it is indeed the motorIndex. Obviously you know already, just a thought of mine ahaha)
Okay, sorry. Quick and last update: IT WORKS. So: implementing and setting enablePins to low is needed for steppers to work (at least using a RAMPS 1.4 board), but the last piece of the puzzle was, of course, my stupidity. Nothing in the config.h needed to be changed (sorry for doubting your skills, master), but during troubleshooting, before adding enablePins, i restarted blender, 'cause: why not? Maybe fixes something, but i forgot to restart it in administrator mode... Big facepalm.
And nothing. That's all. Sorry for bothering you. I hope that at least someone find this helpful.
Now trying to implement a homing sequence. Wish me luck!
hello sir, i have a problem when i try to connect my blender to arduino. it say something like "python could not open port access is denied" i have no serial monitor in Arduino IDE, and still like this.. any suggestions?
Did you also post an issue to the github? I can track it from there. You say you have no serial monitor in Arduino IDE, are you sure the Arduino is being detected when you plug it into your computer (if not there might be a hardware issue with the board or with your cable)? If Arduino IDE cannot detect the board, then MarIOnette will also not be able to detect.
I followed the video. at 30:47 you transition to the Build. When you come back to Blender, you have a VERY different setup. I have exact same servos and Print. This does not work. What changed from before the Build and when you came back to Blender?
Hi, I added a slider that controls whether the IK bone follows a path or is free to move. The fully rigged .blend file is in the github and has this change. I did not include this in the Blender tutorial because it was already getting very long, but I mention it at 36:09. It's not necessary to get the model working; it's just a bonus to showcase another form of controlling the rig.
Not installing for some reason. It's in my Addons menu, in grey, not clickable. Using Blender 3.4
Error: Traceback ModuleNotFoundError????? If I can't Copy and Paste something , I'm usually out of luck.
Any advice would be appreciated.
Hi, could you log the issue to the github so I can track it better - github.com/knee-koh/MarIOnette/issues? If you are trying to install MarIOnette on windows, please launch Blender in Administrator Mode (right click the Blender icon on your desktop and select the corresponding option). From there install the add on as usual.
@@knee-koh Ok was able to install MarIOnette on two of my other PC's successfully.
The 1st computer I tried it on didn't work, cause I previously, accidentally, deleted
some critical files I may have needed to run my PC properly, gotta get that looked at.
Looking forward using the addon now, in Blender, Thanks.
what is config.h? Where can I get it?
Hi, config.h gets generated automatically when you hit the "Sync" button in the MarIOnette panel. That button will generate an Arduino .ino file and a config.h file into a folder you specify. When you open the .ino file, Arduino should open with the config file automatically.
@@knee-koh thanks, because I thought you forgot to add this file. thanks for the help
Is Marinette up to date to the latest Blender and Arduino versions ?
It should be! The latest Blender version I tested is 4.1.1 (latest stable release as of June 10, 2024). The Arduino version shouldn't affect functionality as long as you use Arduino IDE 2.0 or later.
@@knee-koh ok great ! Thank you btw I have been learning how to use it little by little every day currently I’m trying to use it to find a walking gait with RL for a bipedal robot. I have RL saved to a saved animation using IK following a path and some reason when I play the animation the servos don’t move, but in the servo set up I can have them manually move by adjusting Min and Max values. Can an animation control servos ?
@@charles26842 Animations should definitely be able to move servos (as long as the MarIOnette panel is open and active when the animation runs). I've seen this issue crop up a few times on knockoff Arduino boards when the USB/Serial port would randomly disconnect and then reconnect. A couple things to try:
- Disconnect from the controller in the panel, reseat the cable, then reconnect
- See if you're getting any warnings or errors in the bottom of the Blender window
If you still have issues, please make a thread in the MarIOnette github with pictures + details (a .blend file would also be ideal so I can test on my setup): github.com/knee-koh/MarIOnette/issues
@@knee-koh Hello again Long time, hope all is well.
I have been working with it for quite a while and have resolved several issues, connection, servo lag. I was wondering if you have an idea on how to use a PWM driver for servos. I'm thinking it would possibly be as simple as redeclaring the servo pin to PWM channel.
@@knee-koh Main code:
/*
MarIOnette template file for Arduino-compatible boards
Tested on Arduino Nano (ATMega 328P), Arduino Uno, Teensy 3.2, Teensy 4.1
*/
#define DEBUG_SETUP 1
#define DEBUG_SERIAL 1
#define DEBUG_SD_PLAYBACK_TEST 0
#include "config.h"
// Create the PWM servo driver object
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
unsigned int counter = 0;
unsigned int howManyBytes = 0;
unsigned int busServoSpeed;
unsigned int readingPositions = 0;
unsigned int playingAnimation = 0;
unsigned long previousMillis = 0;
const long interval = 200; // Increased interval for non-blocking delay
void readSerialBytes() {
int debugOut = 0; // Minimized debug output
char inByte;
while (Serial.available() > 0) {
char mode = Serial.read();
if (debugOut) {
Serial.print("Mode: ");
Serial.println(mode);
}
// Blender sending data...
if (mode == 'A' || mode == 'B') {
counter = 0;
if (IS_AVR) {
delay(SERIAL_DELAY);
} else {
delayMicroseconds(SERIAL_DELAY);
}
// Read in first bytes to get message length
char one = Serial.read();
if (IS_AVR) {
delay(SERIAL_DELAY);
} else {
delayMicroseconds(SERIAL_DELAY);
}
char two = Serial.read();
if (mode == 'A') {
howManyBytes = word(one, two) + expectedSpeedBytes;
} else {
howManyBytes = word(one, two);
}
if (debugOut) {
Serial.print("Expecting bytes: ");
Serial.println(howManyBytes);
}
if (howManyBytes > 64) { // Check for potential buffer overflow
if (debugOut) {
Serial.println("Error: howManyBytes exceeds buffer size");
}
return;
}
char tempBuffer[howManyBytes];
unsigned long timeout = millis() + 100; // Timeout to prevent infinite loops
while (Serial.available() < howManyBytes && millis() < timeout) {
// wait until we have enough data
}
if (Serial.available() >= howManyBytes) {
for (int i = 0; i < howManyBytes; i++) {
tempBuffer[i] = Serial.read();
}
// Right amount of bytes received, set motors and LEDs
if (debugOut) {
Serial.println("Success! Data received: ");
for (int i = 0; i < howManyBytes; i++) {
char buffer[4];
sprintf(buffer, "%02X ", tempBuffer[i]);
Serial.print(buffer);
}
Serial.println();
}
if (mode == 'A') {
updateMotorsAndLEDs(tempBuffer, 0);
busServoSpeed = word(tempBuffer[0], tempBuffer[1]);
} else {
updateMotorsAndLEDs(tempBuffer, 1);
busServoSpeed = 0;
}
} else {
if (debugOut) {
Serial.println("Timeout waiting for data");
}
while (Serial.available()) {
Serial.read(); // Clear the buffer
}
}
} else if (mode == 'P' && !playingAnimation && SD_ENABLE) {
// Play back file from SD card
SDHelper(1);
} else if (mode == 'S' && playingAnimation && SD_ENABLE) {
// Stop file playback
SDHelper(0);
if (debugOut) {
Serial.println("Animation stopped by serial");
}
} else if (mode == 'R' && !readingPositions && SD_ENABLE) {
// IN PROGRESS!!!
// Read values from dynamixels or bus servos
if (TOTAL_BUS_SERVOS > 0 || TOTAL_DYNAMIXELS > 0) {
if (debugOut) {
Serial.println("Reading values from dynamixels or bus servos");
}
// Read how long the animation is and at what FPS it runs
//readingPositions = 1;
//Serial.parseInt();
//totalFrames = Serial.parseInt();
//FPS = Serial.parseInt();
//frameInterval = 1000*1000/FPS; // In microseconds
//animationTimer = 0;
} else {
if (debugOut) {
Serial.println("No bus servos or dynamixels configured!");
}
}
} else if (mode == 'Z' && readingPositions) {
// Cancel position reads
readingPositions = 0;
}
}
}
void setup() {
// Start Serial monitor
Serial.begin(BAUD_RATE_SERIAL);
if (DEBUG_SETUP) {
Serial.println("Starting MarIOnette initialization...");
}
// Initialize PWM driver
pwm.begin();
pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates
// Perform setup, which gets dynamically generated by MarIOnette
setupAll();
if (DEBUG_SETUP) {
Serial.println("Setup finished!");
}
}
void loop() {
// Check for serial data and update motors and LEDs
readSerialBytes();
// Handle animations
if (playingAnimation) {
playAnimationFile();
}
// Update steppers
updateSteppers();
// Non-blocking delay for smooth servo movement
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
// Call any functions that require timing here
}
}
void setupAll() {
for (int i = 0; i < TOTAL_MOTORS; i++) {
// Servos
if (motor_values[i][0] == 1) {
// Use PWM driver for servos
if (DEBUG_SETUP) {
Serial.print("Servo ");
Serial.print(i);
Serial.print(" on PWM channel ");
Serial.println(i);
}
}
// PWM Pin
if (motor_values[i][0] == 2) {
pinMode(motor_values[i][1], OUTPUT);
}
// ON/OFF Pin
if (motor_values[i][0] == 3) {
pinMode(motor_values[i][1], OUTPUT);
}
// PWM Bi-Directional
if (motor_values[i][0] == 4) {
pinMode(motor_values[i][1], OUTPUT);
pinMode(motor_values[i][2], OUTPUT);
}
}
}
void updateMotorsAndLEDs(char frame_buffer[], int mode) {
int servo_index = 0;
int stepper_index = 0;
for (int i = 0; i < TOTAL_MOTORS; i++) {
int offset = i * 2;
// Speed bytes are sent in case we have bus servos...
if (mode == 0) {
offset = i * 2 + expectedSpeedBytes;
}
unsigned int motor_value = word(frame_buffer[offset], frame_buffer[offset + 1]);
// Min and Max values
if (motor_value > motor_values[i][9] && motor_values[i][8] != 0 && motor_values[i][9] != 0) {
motor_value = motor_values[i][9];
} else if (motor_value < motor_values[i][8] && motor_values[i][8] != 0 && motor_values[i][9] != 0) {
motor_value = motor_values[i][8];
}
// Set servo position using PWM driver
if (motor_values[i][0] == 1) {
int pwm_value = map(motor_value, 691, 1667, 150, 600); // Adjust the range as needed
pwm.setPWM(i, 0, pwm_value);
Serial.print("Setting PWM for Servo ");
Serial.print(i);
Serial.print(" on channel ");
Serial.print(i);
Serial.print(" to value ");
Serial.println(pwm_value);
servo_index++;
}
// Set PWM value
if (motor_values[i][0] == 2) {
analogWrite(motor_values[i][1], map(motor_value, 0, 4000, 0, ANALOG_MAX));
}
// Set ON/OFF value
if (motor_values[i][0] == 3) {
if (motor_value > 0) {
digitalWrite(motor_values[i][1], HIGH);
} else {
digitalWrite(motor_values[i][1], LOW);
}
}
// Set Bi-directional PWM
if (motor_values[i][0] == 4) {
if (motor_values[i][3] == 1) {
if (motor_value > ANALOG_MAX / 2) {
analogWrite(motor_values[i][1], map(motor_value, ANALOG_MAX / 2, ANALOG_MAX, 0, ANALOG_MAX));
digitalWrite(motor_values[i][2], HIGH);
} else {
analogWrite(motor_values[i][1], map(motor_value, ANALOG_MAX / 2, 0, 0, ANALOG_MAX));
digitalWrite(motor_values[i][2], LOW);
}
} else {
if (motor_value > ANALOG_MAX / 2) {
analogWrite(motor_values[i][2], map(motor_value, ANALOG_MAX / 2, ANALOG_MAX, 0, ANALOG_MAX));
digitalWrite(motor_values[i][1], LOW);
} else {
analogWrite(motor_values[i][1], map(motor_value, ANALOG_MAX / 2, 0, 0, ANALOG_MAX));
digitalWrite(motor_values[i][2], LOW);
}
}
}
}
}
void playAnimationFile() {}
void SDHelper(int mode) {}
void readAnimationFile() {}
void updateSteppers() {}
Hello, I'm an artificial intelligence student, and I'm working on an intelligent wheelchair, i want to add some sensors to it using blender then a simulation and collect data
So i can choose to perfect sensor for the project
Is that possible using blender, or maybe you can suggest another tool
Thank you!
Hi, that might be challenging to do inside Blender since the simulation tools in the program are intended for more artistic purposes than real-world scenarios. I would suggest you look at something like ROS, Gazebo or ROS MoveIt, which are more appropriate for real-world robotic applications that rely on accurate physics and can manipulate data from the real world.