<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Topics tagged with m5stack-basic]]></title><description><![CDATA[A list of topics that have been tagged with m5stack-basic]]></description><link>https://community.m5stack.com/tags/m5stack-basic</link><generator>RSS for Node</generator><lastBuildDate>Fri, 13 Mar 2026 11:45:08 GMT</lastBuildDate><atom:link href="https://community.m5stack.com/tags/m5stack-basic.rss" rel="self" type="application/rss+xml"/><pubDate>Invalid Date</pubDate><ttl>60</ttl><item><title><![CDATA[myArm M &amp; C: Advanced Solutions for Diverse Robotic Applications]]></title><description><![CDATA[<p dir="auto"><em>Special thanks to M5stack basic for a very suitable device embedded in a robotic arm!</em></p>
<h2>Introduction</h2>
<p dir="auto">In recent years, many projects similar to Stanford University’s Alopha robot project have emerged, primarily focusing on learning by mimicking human motion trajectories to achieve human-like artificial intelligence. The Alopha robot, through advanced algorithms and sensor technology, can precisely replicate human actions, collecting data and learning from it to enhance its performance in various tasks. This imitation learning approach not only enables robots to excel in industrial automation but also shows significant potential in educational and research fields. Against this backdrop, Elephant Robotics has introduced the myArm M &amp; C series robotic arms, further advancing humanoid robot technology.</p>
<h2>Innovative Solutions for the Future</h2>
<p dir="auto">With the rapid advancement of robotics technology, Elephant Robotics has introduced the groundbreaking myArm 650 M &amp; C series robotic arms, offering unprecedented flexibility and precision for educational, research, and industrial applications. These high-performance robotic arms are not only powerful but also flexible and user-friendly, making them suitable for a variety of applications and providing ideal solutions. Let’s delve into the myArm 650 M &amp; C series products!</p>
<h2>Products</h2>
<p dir="auto"><strong>myArm C650</strong></p>
<p dir="auto"><img src="/assets/uploads/files/1716194677276-3ed1d8aa-ac81-404a-abbd-1803921d0b23-image.png" alt="0_1716194676691_3ed1d8aa-ac81-404a-abbd-1803921d0b23-image.png" class=" img-fluid img-markdown" /><br />
The myArm C650 is a versatile 6-degree-of-freedom robotic motion information collection device, equipped with a fingertip controller and two intelligent buttons. The “C” stands for Controller. It can output end coordinates or joint angles at 50 Hz. Designed for education, research, and industrial data collection, its flexibility and highly modular design make it suitable for various complex operations and tasks. It can be extended to a 7-degree-of-freedom data collector.<br />
<img src="/assets/uploads/files/1716194697520-61be2f8b-05ce-480e-961c-8c5c40150726-image.png" alt="0_1716194697038_61be2f8b-05ce-480e-961c-8c5c40150726-image.png" class=" img-fluid img-markdown" /><br />
<strong>myArm M750</strong></p>
<p dir="auto"><img src="/assets/uploads/files/1716194745773-68c1ce0f-cde7-4d3e-a3a0-25c759183095-image.png" alt="0_1716194745224_68c1ce0f-cde7-4d3e-a3a0-25c759183095-image.png" class=" img-fluid img-markdown" /><br />
The myArm M750 is a general-purpose intelligent six-degree-of-freedom robotic arm with a reach of 750 mm and a rated load capacity of 500 g, with a maximum capacity of up to 1 kg. It comes with a 1-degree-of-freedom parallel end effector (gripper). The “M” stands for Master controller. It is suitable for applications requiring complex motion control, precise positioning, and high programmability.<br />
<img src="/assets/uploads/files/1716194767167-db267f91-b177-41f0-b5b5-27e17ef2397d-image.png" alt="0_1716194766688_db267f91-b177-41f0-b5b5-27e17ef2397d-image.png" class=" img-fluid img-markdown" /></p>
<h2>Product Features</h2>
<p dir="auto">● High-Speed Data Output: Both the myArm C650 and M750 can output end coordinates or joint angles at a frequency of 50 Hz, providing real-time motion data to ensure smooth operation.</p>
<p dir="auto">● Flexibility and Modular Design: The robotic arms feature a highly modular design, allowing users to customize and expand according to their needs, making them suitable for a wide range of applications.</p>
<p dir="auto">● Robust Load Capacity: The myArm M750 has a reach of 750 mm and a load capacity of 500 g, with a maximum capacity of up to 1 kg, making it suitable for complex industrial tasks.</p>
<p dir="auto">● Programming and Control: Supporting Python and ROS, the arms offer powerful programming capabilities and flexible control options, making them ideal for education and industrial automation fields.</p>
<p dir="auto">● Strong Compatibility: The arms support various sensors and end effectors, including cameras and IMUs, further enhancing data collection and processing capabilities.</p>
<h2>AI Learning and Training Project</h2>
<p dir="auto">Recently, many projects similar to Stanford University’s Alopha robot project have emerged. These projects mainly involve learning by mimicking human motion trajectories. By recording trajectory data and conducting extensive training, the Alopha robot can autonomously perform certain household chores, such as cooking, washing dishes, and folding clothes.<br />
<a href="https://youtu.be/HaaZ8ss-HP4" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/HaaZ8ss-HP4</a><br />
The key elements of the entire project are the full-body remote control system, human demonstration learning, and collaborative training of datasets. To this end, we have also launched a corresponding humanoid composite suite, equipped with two sets of myArm M &amp; C robotic arms and the Elephant Robotics mobile platform for mobility.<br />
<img src="/assets/uploads/files/1716194802404-c6096d4c-32f3-4892-9e7c-f08ca065e6b1-image.png" alt="0_1716194801911_c6096d4c-32f3-4892-9e7c-f08ca065e6b1-image.png" class=" img-fluid img-markdown" /><br />
Now, let me demonstrate how to operate using a set of myArm M &amp; C.<br />
<a href="https://youtu.be/-sLegg0wSUQ" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/-sLegg0wSUQ</a><br />
The myArm M650 is essentially a 6+1-axis robotic arm: 6 degrees of freedom for the arm itself and 1 for the additional end gripper controller. To ensure better data synchronization, we have also designed the myArm C to be of the same type but different sizes.<br />
<a href="https://youtu.be/AlKLbohyA4E" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/AlKLbohyA4E</a><br />
You can see that the synchronous remote control operation is quite smooth. This is mainly due to the myArm's ability to output terminal coordinates and joint angles at a rate of 50 Hz, providing users with real-time motion data. Let's try grasping some parts to experience its effectiveness.<br />
<a href="https://youtu.be/DMZSXuJ_lA0" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/DMZSXuJ_lA0</a><br />
To achieve functionality similar to the Alopha robot, we have completed two parts: the remote control system and human demonstration learning. The most crucial part remaining is the collaborative training of datasets.</p>
<p dir="auto">Collaborative Training of Datasets:<br />
Collaborative training (co-training) is a machine learning technique particularly suitable for multi-task learning and ensemble learning. The core idea is to use multiple different datasets or data perspectives to jointly train a model, thereby improving the model's performance on specific tasks.<br />
Here is a detailed introduction about the dataset:<br />
<a href="https://www.inceptivemind.com/meet-mobile-aloha-your-housekeeping-robot/36176/" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.inceptivemind.com/meet-mobile-aloha-your-housekeeping-robot/36176/</a><br />
The entire Aloha project is open source, so we can find how their team conducted the training online. The specific steps are as follows:</p>
<p dir="auto">1.Initial Model Training: First, train the initial model using an existing static dataset. This model can perform dual-hand static tasks.</p>
<p dir="auto">2.Mobile Operation Data Collection: Then, collect demonstration data of the robot performing tasks in a mobile environment using the full-body remote control system.</p>
<p dir="auto">3.Joint Training: Combine static and dynamic datasets for training. By integrating data from both scenarios, the model can learn a broader range of task<br />
characteristics, improving its generalization ability and success rate on new tasks.</p>
<p dir="auto">The data involved includes tasks such as grasping and placing objects, tidying up the table, moving speed, opening and closing cabinet doors, camera images, LiDAR data, and IMU data.<br />
To meet the needs of most projects, the myArm M &amp; C series offers significant performance advantages, including high-frequency data transmission at a rate of 50 frames per second. It also has specialized software to collect relevant data, such as the height of objects, the height of the table, and the speed of movement.<br />
Additionally, the myArm is equipped with multiple sensors, such as cameras and IMUs, with the ultimate goal of acquiring precise datasets for training.</p>
<h2>Application Scenarios</h2>
<p dir="auto">The project mentioned above is just one example. Our robotic arm can do much more and can be used in conjunction with quadruped robots for tasks like intelligent garbage collection.</p>
<p dir="auto"><img src="/assets/uploads/files/1716194885706-ab2d7c90-37ea-4cc8-b006-984709a3d42e-image.png" alt="0_1716194885106_ab2d7c90-37ea-4cc8-b006-984709a3d42e-image.png" class=" img-fluid img-markdown" /><br />
<strong>Standalone Robotic Arm Applications:</strong></p>
<p dir="auto">Medical and Rehabilitation<br />
● Surgery Simulation: In medical training, the myArm M &amp; C can simulate surgical procedures, helping surgeons practice and train before actual operations.<br />
● Rehabilitation Assistance: It can assist in the rehabilitation of patients by facilitating hand and arm recovery exercises, with programmable different rehabilitation movement trajectories.<br />
<img src="/assets/uploads/files/1716194934832-9424ed1f-042d-40eb-997e-a72b007a5e63-image.png" alt="0_1716194934339_9424ed1f-042d-40eb-997e-a72b007a5e63-image.png" class=" img-fluid img-markdown" /><br />
Education and Training<br />
● Robotics Programming Courses: In schools and training institutions, the myArm M &amp; C can be used as a teaching tool, helping students learn robotic programming and control. Through programming tasks, students can master how to control the robot's movements and perform complex operations.<br />
● Laboratory Experiments: Used in university and research institution laboratories for the study of robotic arm kinematics and dynamics. Students can conduct precise motion control experiments and analyze the robot's performance.<br />
<img src="/assets/uploads/files/1716194991916-37eb8ccc-a02b-4c88-8a91-726bb3d0ff2b-image.png" alt="0_1716194991417_37eb8ccc-a02b-4c88-8a91-726bb3d0ff2b-image.png" class=" img-fluid img-markdown" /><br />
Combined Applications:</p>
<p dir="auto">Integration with Mobile Robots<br />
● Automated Warehouse System: Combine the myArm M &amp; C with mobile robots (such as Elephant Robotics mobile platforms) to create an automated warehouse system. The mobile robots handle the transportation of items, while the myArm handles the picking and placing, achieving efficient item management and sorting.<br />
● Logistics and Transportation: In logistics centers, the combination of the myArm and mobile platforms can automate the sorting and transportation of packages, improving logistics efficiency.<br />
● Sentinel Patrol: Paired with quadruped robots, it can perform patrol inspections in parks and clean up trash when detected.</p>
<h2>Summary</h2>
<p dir="auto">The myArm M &amp; C series robotic arms, with their high flexibility, precision, and modular design, demonstrate broad application potential in education, research, industry, and home environments. When used independently, these robotic arms excel in tasks such as precision assembly, quality inspection, educational training, and medical rehabilitation, showcasing their exceptional performance in complex operations. When combined with other robots, such as mobile robots or other robotic arms, the myArm M &amp; C can build efficient automated systems, enabling more complex task allocation and execution. Additionally, these robotic arms can be applied in artistic creation and smart home setups, further expanding their use cases and creative possibilities.</p>
]]></description><link>https://community.m5stack.com/topic/6488/myarm-m-c-advanced-solutions-for-diverse-robotic-applications</link><guid isPermaLink="true">https://community.m5stack.com/topic/6488/myarm-m-c-advanced-solutions-for-diverse-robotic-applications</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Transforming Camera Angles with Robotic Arm Technology]]></title><description><![CDATA[<h2>Introduction</h2>
<p dir="auto">Have you ever encountered a situation like this: when you're ready to shoot a video with your smartphone or camera, you've already envisioned the perfect shot in your mind, but due to practical limitations, you can't capture the angle you desire? This situation can be frustrating. For example, if you want to shoot from the perspective of an ant on the ground, the lens needs to be on the same level as the ant, which is not only difficult in practice but often hard to achieve.</p>
<p dir="auto">Although there are many stabilizing devices on the market, such as gimbal stabilizers, to assist in achieving steady and multi-angle shooting effects, in this article, I will explore a unique solution: mounting the smartphone on the end of a robotic arm to shoot, aiming to capture those special viewpoints that traditional methods struggle to grasp. This attempt is not only designed to overcome the physical limitations encountered during the shooting process but also hopes to innovate technologically to expand our imagination and practice of photography angles.<br />
<a href="https://www.youtube.com/watch?v=xXq9_Nu9djs" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.youtube.com/watch?v=xXq9_Nu9djs</a><br />
Equipment<br />
myCobot 320 M5stack<br />
The myCobot 320, a collaborative robot arm with six degrees of freedom, has become a highlight in its field thanks to its unique design and high-precision servo motors. This robotic arm has a maximum working radius of 350mm and a maximum end load capacity of 1000g, making it suitable for a wide range of application scenarios. The myCobot 320 not only supports flexible visual development applications but also provides in-depth analysis of mechanical motion principles, offering users 12 standard 24V industrial IO interfaces to meet various development needs.<br />
<img src="/assets/uploads/files/1712828816476-d37047f6-4a08-44d7-83cf-004386a82534-image-resized.png" alt="0_1712828807002_d37047f6-4a08-44d7-83cf-004386a82534-image.png" class=" img-fluid img-markdown" /><br />
Its openness is extremely high, compatible with most mainstream operating systems and programming languages, including Python and ROS, offering developers a great deal of flexibility and freedom. Whether in education, research and development, or industrial applications, the myCobot 320 provides strong support, making innovation and application development more convenient and efficient.</p>
<h2>myCobot Pro Phone Holder</h2>
<p dir="auto">It can be mounted on the end of the myCobot 320 and myCobot Pro 630 robotic arms, capable of securely holding a smartphone in place.<br />
<img src="/assets/uploads/files/1712828831755-8669db63-2b0c-4195-87c5-dd2d31eed82e-image.png" alt="0_1712828822428_8669db63-2b0c-4195-87c5-dd2d31eed82e-image.png" class=" img-fluid img-markdown" /><br />
<img src="/assets/uploads/files/1712828835301-60971631-9d33-400c-ab15-01161b1d1879-image-resized.png" alt="0_1712828826021_60971631-9d33-400c-ab15-01161b1d1879-image.png" class=" img-fluid img-markdown" /></p>
<h2>Initial Attempt</h2>
<p dir="auto">Installing the Phone Holder<br />
<img src="/assets/uploads/files/1712828848291-d8bd02fe-863b-4171-ae1b-c2b9592f44be-image.png" alt="0_1712828839009_d8bd02fe-863b-4171-ae1b-c2b9592f44be-image.png" class=" img-fluid img-markdown" /><br />
<a href="https://youtu.be/QvcSwkRnooY" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/QvcSwkRnooY</a></p>
<h2>Shooting Video</h2>
<p dir="auto">Programming joint control for the robotic arm, let's see how it performs.<br />
<a href="https://youtu.be/b-FiXHTFsrw" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/b-FiXHTFsrw</a><br />
Although the robotic arm's movement trajectory shown in the video appears simple, in reality, adjusting these trajectory points still requires a considerable amount of time, and the results may not always be ideal. Therefore, I am considering whether there is a better solution, such as setting several motion modes and pre-planning the robotic arm's shooting path. This would not only make effective use of the robotic arm to assist in shooting but also provide a more efficient deployment method.</p>
<h2>Programming Challenge</h2>
<p dir="auto">Development Needs Analysis<br />
The equipment to be used is as follows:<br />
<img src="/assets/uploads/files/1712829032991-3c3440ba-7ddd-4feb-af49-edca1a0bf561-image-resized.png" alt="0_1712829023682_3c3440ba-7ddd-4feb-af49-edca1a0bf561-image.png" class=" img-fluid img-markdown" /><br />
Requirements Optimization:<br />
The goal is to design a series of innovative video shooting methods for static objects. The initial plan adopts three approaches:</p>
<ol>
<li>Using the smartphone fixed at the end of the robotic arm to achieve 360° panoramic video shooting of the object.</li>
<li>Creating a visual effect that smoothly advances from a distance to close to the object, simulating a "zoom-in" effect.</li>
<li>Achieving rapid rotation and movement at the end of the robotic arm to capture dynamic scenes.</li>
</ol>
<p dir="auto">To precisely control the shooting process, the plan is to utilize OpenCV machine vision algorithms and the AVFoundation iOS framework, controlling the exact movements of the robotic arm with Python scripts. We will identify the dimensions of the object through the smartphone camera, thereby calculating the ideal distance between the end of the robotic arm and the object. Based on this distance, we will design a corresponding robotic arm movement algorithm to ensure the best visual effects during the shooting process.<br />
<img src="/assets/uploads/files/1712829052588-48693360-4537-4a64-8b99-81b3b8a1a9ac-image-resized.png" alt="0_1712829043327_48693360-4537-4a64-8b99-81b3b8a1a9ac-image.png" class=" img-fluid img-markdown" /></p>
<h2>YOLOv5 Vision Algorithm</h2>
<p dir="auto">To save time, we will not train the machine vision algorithm ourselves to recognize specific objects. Instead, we will directly use the YOLOv5 library, which has been trained and optimized by other developers, to achieve accurate detection of target objects.</p>
<pre><code>import cv2
import torch
from pathlib import Path
from models.experimental import attempt_load
from utils.general import non_max_suppression, scale_coords
from utils.torch_utils import select_device, time_synchronized

def detect_apples(img_path):
    device = select_device('')
    weights = 'yolov5s.pt'
    model = attempt_load(weights, map_location=device)
    img0 = cv2.imread(img_path)  # BGR
    img = img0[:, :, ::-1]  # RGB
    img = torch.from_numpy(img).to(device)
    img = img.float()  # uint8 to fp16/32
    img /= 255.0  # 0 - 255 to 0.0 - 1.0
    if img.ndimension() == 3:
        img = img.unsqueeze(0)

    # Inference
    t1 = time_synchronized()
    pred = model(img)[0]
    # Apply NMS
    pred = non_max_suppression(pred, 0.4, 0.5, classes=None, agnostic=False)
    t2 = time_synchronized()
    print(f'Inference time: {(t2 - t1):.3f}s')

    # Process detections
    for i, det in enumerate(pred):  # detections per image
        gn = torch.tensor(img0.shape)&lsqb;&lsqb;1, 0, 1, 0&rsqb;&rsqb;  # normalization gain whwh
        if len(det):
            det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img0.shape).round()
            for *xyxy, conf, cls in reversed(det):
                label = f'{model.names[int(cls)]} {conf:.2f}'
                plot_one_box(xyxy, img0, label=label, color=(255, 0, 0))
    return img0

def plot_one_box(xyxy, img, color=None, label=None, line_thickness=None):
    # Plots one bounding box on image img
    tl = (
        line_thickness or round(0.002 * max(img.shape[0:2])) + 1
    )  # line/font thickness
    color = color or [random.randint(0, 255) for _ in range(3)]
    c1, c2 = (int(xyxy[0]), int(xyxy[1])), (int(xyxy[2]), int(xyxy[3]))
    cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)
    if label:
        tf = max(tl - 1, 1)  # font thickness
        t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
        c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3
        cv2.rectangle(
            img, c1, c2, color, -1, cv2.LINE_AA
        )  # filled
        cv2.putText(
            img,
            label,
            (c1[0], c1[1] - 2),
            0,
            tl / 3,
            [225, 255, 255],
            thickness=tf,
            lineType=cv2.LINE_AA,
        )
    return img

if __name__ == '__main__':
    img_path = 'apple.jpg'  
    result_img = detect_apples(img_path)
    cv2.imshow('Result', result_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
</code></pre>
<p dir="auto"><img src="/assets/uploads/files/1712829086049-2d0ae8c5-3a45-425e-bc32-19dee707a30a-image-resized.png" alt="0_1712829076653_2d0ae8c5-3a45-425e-bc32-19dee707a30a-image.png" class=" img-fluid img-markdown" /><br />
Robotic Arm Motion Control Algorithm<br />
Methods for controlling the robotic arm:</p>
<h1>This method controls the movement of the robotic arm's joints.</h1>
<p dir="auto">mc.send_angles([angle_list],speed)</p>
<pre><code># This method uses coordinates to control the robotic arm's movement in space.
mc.send_coords([coords_list],speed,mode)
example:
mc.send_angles([0,0,0,0,0,0],100)
time.sleep(2)
mc.send_coords([(-3.6), 30.32, (-45.79), (-46.84), 97.38, 0.35],100,1)
</code></pre>
<p dir="auto">After obtaining the dimensions of the object, define a reasonable position for the end of the robotic arm relative to the object.</p>
<pre><code>def calculate_angles_for_distance(distance):
    #Calculate the joint angles of the robotic arm based on the ideal distance.
    # The calculations here need to be adjusted based on actual conditions and physical parameters
    return [0, -10, distance * 0.1, 0, 30, 0]  

def calculate_adjusted_angles(action_angles):
    # Calculate new angles based on the coordinate adjustments that may be needed after a specific action
    # This is just an example, and the specific logic should be adjusted as needed.
    return [angle * 1.1 for angle in action_angles]  
</code></pre>
<p dir="auto">Then select the motion control corresponding to the chosen mode.</p>
<pre><code>#For 360° Panoramic Shooting:
# Define the specific shooting mode
def shoot_mode_360(ideal_distance):
    print("excuse 360")
    # First, move to the ideal shooting position.
    move_to_ideal_position(ideal_distance)
    # Handle the ideal distance.
    ideal_ratio =  ratio
    # Perform the specific actions for 360° panoramic shooting.
    mc.send_angles([0, 0, 0, 0, 0, 0], speed=15)
    time.sleep(1)
    mc.send_coords([angle * ratio for angle in angles_list]
，15)
    time.sleep(1)
    mc.send_coords([angle * ratio for angle in angles_list]
，15)
    time.sleep(1)
    mc.send_coords([angle * ratio for angle in angles_list]
，15)
</code></pre>
<h2>Invoking the Smartphone Camera</h2>
<p dir="auto">In the development process, as I attempted to invoke the smartphone camera interface to realize the automatic shooting function, I encountered a series of challenges. As my first deep exploration into the AVFoundation iOS framework, with the goal of activating and controlling the smartphone's camera, I found that I had not yet fully succeeded in implementing this function. The current difficulties mainly focus on how to accurately call the camera for video shooting and how to compensate for possible image stretching during the shooting process through software adjustments, which requires precise control over the movement of the robotic arm. These issues mark the direction of my subsequent research and require me to continue delving into the use of the AVFoundation framework, especially its specific methods for controlling the camera, and explore how to integrate these controls into the adjustment of the robotic arm's movement to ensure the video quality meets expectations.</p>
<h2>Summary</h2>
<p dir="auto">As this project record comes to an end, I realize that although there are many areas for improvement, attempting to make two independent devices work together under different frameworks has been a valuable experience for me. Indeed, the entire project has not yet reached the ideal state in my mind. However, I believe the direction explored by this project has great potential, considering that there are already professional photography robotic arms on the market capable of producing impressive results, which reinforces my belief in the potential value of the project.<br />
The application of robotic arms has already permeated our daily lives, playing an increasingly important role whether in industrial production, daily services, or in the field of artistic creation. With the continuous advancement and popularization of artificial intelligence technology, the combination of AI and robotics will undoubtedly become an important trend in the future development of technology. I have great expectations for the future development of robotics technology and believe that they will display amazing capabilities and creativity in more fields in the future.<br />
If you are interested in my project, or have any ideas and suggestions, I warmly welcome your communication. Your feedback will provide valuable help for me to continue improving and perfecting this project.</p>
]]></description><link>https://community.m5stack.com/topic/6318/transforming-camera-angles-with-robotic-arm-technology</link><guid isPermaLink="true">https://community.m5stack.com/topic/6318/transforming-camera-angles-with-robotic-arm-technology</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Building AIRobot Leveraging ChatGPT for Smarter Robots myCobot 280 M5Stack-Basic]]></title><description><![CDATA[<p dir="auto">As the control core of the embedded robotic arm, M5stack-basic is very useful and helps a lot！</p>
]]></description><link>https://community.m5stack.com/topic/6283/building-airobot-leveraging-chatgpt-for-smarter-robots-mycobot-280-m5stack-basic</link><guid isPermaLink="true">https://community.m5stack.com/topic/6283/building-airobot-leveraging-chatgpt-for-smarter-robots-mycobot-280-m5stack-basic</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[EchoActions: Connecting thougths and Robotic Arm M5Stack]]></title><description><![CDATA[<p dir="auto"><em>This article is edited and reprinted with authorization from the author, kimizuka.<br />
Original article link: <a href="https://blog.kimizuka.org/entry/2024/02/01/141808" target="_blank" rel="noopener noreferrer nofollow ugc">https://blog.kimizuka.org/entry/2024/02/01/141808</a></em><br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/0/5/05df83ba6703369f30333ac96c2b484afe279f24.gif" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>Introduction</h2>
<p dir="auto">Translate AirPods through the iPhone app to Express, then through python-shell to pymycobot, and finally synchronize with myCobot to synchronize the rotation angle of AirPods with the posture of myCobot 🤖.<br />
<img src="/assets/uploads/files/1708939784052-503ad5a1-9d02-4904-abc0-e02b369867ae-image-resized.png" alt="0_1708939783546_503ad5a1-9d02-4904-abc0-e02b369867ae-image.png" class=" img-fluid img-markdown" /><br />
Although it's unclear if there's a demand, I will provide a rough outline of the source code.</p>
<h2>Project Structure</h2>
<p dir="auto">This project primarily employs technologies such as headphone-motion, web servers, the express framework of node.js, python-shell, and pymycobot. Here is a brief introduction to these technologies:<br />
<strong>1.Headphone-Motion:</strong> Headphone Motion is a project that utilizes specific technology to track and utilize user head movements. Although the specifics may depend on the implementation method and platform used (such as iOS), it mainly demonstrates how to capture head movement data by connecting to the device's headphones (especially those smart headphones with built-in sensors). A more intuitive effect of this can be seen in the Headphone Motion Unity Plugin made by GitHub user anastasiadeana. It is capable of real-time tracking of the user's head movements, including tilting and rotating, which is a core technology of this project.<br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/1/f/1f6f76ad65017b7dffd2609f2bc633ec444ef3bc.gif" alt="alt text" class=" img-fluid img-markdown" /><br />
<strong><a href="http://2.Web" target="_blank" rel="noopener noreferrer nofollow ugc">2.Web</a> Server:</strong> There are many types of servers, which provide data, services, or applications to other applications or devices. Servers perform tasks such as processing data requests, hosting websites, storing information, running business applications, and so on. In this project, the web server mainly handles receiving head movement data from the iOS application and passing these data to the script controlling the mycobot robot arm.</p>
<p dir="auto"><strong>3.Express-Node.js:</strong> Express is a fast, open, minimalistic web application framework for Node.js. It is designed for building web applications and APIs. It allows developers to set up middleware to respond to HTTP requests in a very fast and simple way, making the development of web applications quicker and easier.<br />
<a href="https://github.com/expressjs/express" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/expressjs/express</a></p>
<p dir="auto"><strong>4.Pymycobot-Python:</strong> pymycobot is a Python library specifically designed for controlling the myCobot robot arm. This library provides a series of functions and interfaces that allow developers to communicate and control the myCobot robot arm directly through Python scripts. Using pymycobot, developers can write code to control the robot arm's movements, adjust its posture, execute preset action sequences, etc., making it widely applicable in education, research, automation, and more.</p>
<h2>iOS App</h2>
<p dir="auto">This application is based on an app I created previously, utilizing react-native-headphone-motion to access the sensors in AirPods through a React Native iOS application.</p>
<p dir="auto">It's an interesting project where, when you are detected bending your head down for a long time while wearing AirPods, a lamenting sound will remind you.<br />
<a href="https://twitter.com/i/status/1745588902981931443" target="_blank" rel="noopener noreferrer nofollow ugc">https://twitter.com/i/status/1745588902981931443</a><br />
<a href="https://blog.kimizuka.org/entry/2024/01/16/105208" target="_blank" rel="noopener noreferrer nofollow ugc">https://blog.kimizuka.org/entry/2024/01/16/105208</a></p>
<p dir="auto">One point to note is the change I made: I added a process to send POST requests to the web server in onDeviceMotionUpdates. Additionally, to avoid overburdening the server with POST requests on every update, I set it up to send a request at a minimum interval of 500ms.</p>
<p dir="auto">App.tsx</p>
<pre><code>useEffect(() =&gt; {
  const delay = 500;
  const handleDeviceMotionUpdates = onDeviceMotionUpdates((data) =&gt; {
     // If the time since the last request is less than 500ms, return
    if (Date.now() - lastUpdateTimeRef.current &lt; delay) {
      return;
    }

    // Post sensor values to the Web server
    axios.post(String(process.env.API_URL), { 
      pitch: data.attitude.pitchDeg || 0,
      roll: data.attitude.rollDeg || 0,
      yaw: data.attitude.yawDeg || 0
    }).then(() =&gt; {
      lastUpdateTimeRef.current = Date.now();
    }).catch((err) =&gt; {
      console.error(err);
      lastUpdateTimeRef.current = Date.now();
    });

    setPitch(data.attitude.pitch);
    setPitchDeg(data.attitude.pitchDeg);
    setRoll(data.attitude.roll);
    setRollDeg(data.attitude.rollDeg);
    setYaw(data.attitude.yaw);
    setYawDeg(data.attitude.yawDeg);
    setGravityX(data.gravity.x);
    setGravityY(data.gravity.y);
    setGravityZ(data.gravity.z);
    setRotationRateX(data.rotationRate.x);
    setRotationRateY(data.rotationRate.y);
    setRotationRateZ(data.rotationRate.z);
    setUserAccelerationX(data.userAcceleration.x);
    setUserAccelerationY(data.userAcceleration.y);
    setUserAccelerationZ(data.userAcceleration.z);
  });

  return () =&gt; {
    handleDeviceMotionUpdates.remove();
  };
}, []);

</code></pre>
<p dir="auto">In the POST request, I used axios, which can send asynchronous HTTP requests to REST endpoints and handle responses.<br />
Therefore, it's also necessary to add module imports.</p>
<pre><code>import axios from 'axios';
</code></pre>
<p dir="auto">Code</p>
<pre><code>import axios from 'axios'; // Added to simplify the POST request
import React, {
  useEffect,
  useRef, // Added to maintain a 500ms interval
  useState,
} from 'react';
import {Button, SafeAreaView, StyleSheet, Text} from 'react-native';
import {
  requestPermission,
  onDeviceMotionUpdates,
  startListenDeviceMotionUpdates,
  stopDeviceMotionUpdates,
} from 'react-native-headphone-motion';

const API_URL = 'http://localhost:3000'; // Fill in the URL to POST

export default function App() {
  const lastUpdateTimeRef = useRef&lt;number&gt;(0); // Added to keep track of the last update time
  const [pitch, setPitch] = useState(0);
  const [pitchDeg, setPitchDeg] = useState(0);
  const [roll, setRoll] = useState(0);
  const [rollDeg, setRollDeg] = useState(0);
  const [yaw, setYaw] = useState(0);
  const [yawDeg, setYawDeg] = useState(0);
  const [gravityX, setGravityX] = useState(0);
  const [gravityY, setGravityY] = useState(0);
  const [gravityZ, setGravityZ] = useState(0);
  const [rotationRateX, setRotationRateX] = useState(0);
  const [rotationRateY, setRotationRateY] = useState(0);
  const [rotationRateZ, setRotationRateZ] = useState(0);
  const [userAccelerationX, setUserAccelerationX] = useState(0);
  const [userAccelerationY, setUserAccelerationY] = useState(0);
  const [userAccelerationZ, setUserAccelerationZ] = useState(0);

  useEffect(() =&gt; {
    const delay = 500; // Store the update interval in a variable
    const handleDeviceMotionUpdates = onDeviceMotionUpdates(data =&gt; {
      if (Date.now() - lastUpdateTimeRef.current &lt; delay) {
        // Return if the update interval is not met
        return;
      }

      // Post sensor values to the Web server
      // Update lastUpdateTimeRef regardless of success or failure
      // For some reason, await was not used
      axios
        .post(String(API_URL), {
          pitch: data.attitude.pitchDeg || 0,
          roll: data.attitude.rollDeg || 0,
          yaw: data.attitude.yawDeg || 0,
        })
        .then(() =&gt; {
          lastUpdateTimeRef.current = Date.now();
        })
        .catch(err =&gt; {
          console.error(err);
          lastUpdateTimeRef.current = Date.now();
        });

      setPitch(data.attitude.pitch);
      setPitchDeg(data.attitude.pitchDeg);
      setRoll(data.attitude.roll);
      setRollDeg(data.attitude.rollDeg);
      setYaw(data.attitude.yaw);
      setYawDeg(data.attitude.yawDeg);
      setGravityX(data.gravity.x);
      setGravityY(data.gravity.y);
      setGravityZ(data.gravity.z);
      setRotationRateX(data.rotationRate.x);
      setRotationRateY(data.rotationRate.y);
      setRotationRateZ(data.rotationRate.z);
      setUserAccelerationX(data.userAcceleration.x);
      setUserAccelerationY(data.userAcceleration.y);
      setUserAccelerationZ(data.userAcceleration.z);
    });

    return () =&gt; {
      handleDeviceMotionUpdates.remove();
    };
  }, []);

  return (
    &lt;SafeAreaView style={styles.container}&gt;
      &lt;Button
        title={'requestPermission'}
        onPress={async () =&gt; {
          await requestPermission();
        }}
      /&gt;
      &lt;Button
        title={'startListenDeviceMotionUpdates'}
        onPress={async () =&gt; {
          await startListenDeviceMotionUpdates();
        }}
      /&gt;
      &lt;Button
        title={'stopDeviceMotionUpdates'}
        onPress={async () =&gt; {
          await stopDeviceMotionUpdates();
        }}
      /&gt;
      &lt;Text&gt;{lastUpdateTimeRef.current}&lt;/Text&gt;
      &lt;Text&gt;{`pitch: ${pitch}`}&lt;/Text&gt;
      &lt;Text&gt;{`pitchDeg: ${pitchDeg}`}&lt;/Text&gt;
      &lt;Text&gt;{`roll: ${roll}`}&lt;/Text&gt;
      &lt;Text&gt;{`rollDeg: ${rollDeg}`}&lt;/Text&gt;
      &lt;Text&gt;{`yaw: ${yaw}`}&lt;/Text&gt;
      &lt;Text&gt;{`yawDeg: ${yawDeg}`}&lt;/Text&gt;
      &lt;Text&gt;{`gravityX: ${gravityX}`}&lt;/Text&gt;
      &lt;Text&gt;{`gravityY: ${gravityY}`}&lt;/Text&gt;
      &lt;Text&gt;{`gravityZ: ${gravityZ}`}&lt;/Text&gt;
      &lt;Text&gt;{`rotationRateX: ${rotationRateX}`}&lt;/Text&gt;
      &lt;Text&gt;{`rotationRateY: ${rotationRateY}`}&lt;/Text&gt;
      &lt;Text&gt;{`rotationRateZ: ${rotationRateZ}`}&lt;/Text&gt;
      &lt;Text&gt;{`userAccelerationX: ${userAccelerationX}`}&lt;/Text&gt;
      &lt;Text&gt;{`userAccelerationY: ${userAccelerationY}`}&lt;/Text&gt;
      &lt;Text&gt;{`userAccelerationZ: ${userAccelerationZ}`}&lt;/Text&gt;
    &lt;/SafeAreaView&gt;
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'white',
  },
});

</code></pre>
<p dir="auto">Actually, it would be more convenient to specify the API_URL directly in the application, but I implemented it this way considering speed.</p>
<h2>Web Server</h2>
<p dir="auto">I set up a local server on my Mac. To operate myCobot, I went through several setup steps, mainly to adapt to Mac computers. These steps included installing drivers for the robot arm, updating the firmware of mycobot 280, and other operations, all detailed in this article.<br />
<a href="https://blog.kimizuka.org/entry/2021/08/10/131812" target="_blank" rel="noopener noreferrer nofollow ugc">https://blog.kimizuka.org/entry/2021/08/10/131812</a><br />
I think creating a web server with Python would be smoother, but based on my skill set, using Node.js is the fastest method. So, I plan to quickly set up the server using Express. Communication with myCobot is conducted through Python, so for this part, I decided to use python-shell to implement it.</p>
<pre><code>require('dotenv').config(); // Used to pass the port of myCobot from outside
const express = require('express');
const { PythonShell } = require('python-shell'); // Used for communicating with myCobot
const app = express();
const http = require('http').Server(app);

const duration = 100; // If the delay (500ms) set on the application side is too small, it will cause problems

app.use(express.json());
app.post('/', (req, res) =&gt; {
  try {
    const angles = [0, 0, 0, 0, 0, 0];

    // For myCobot's joint information, refer to page 13 of https://www.elephantrobotics.com/wp-content/uploads/2021/03/myCobot-User-Mannul-EN-V20210318.pdf
    // The array stores the 6 joints in order from the bottom up
    // Each joint has a definite range of motion; ensure not to exceed this range    
    angles[0] = Math.max(-90, Math.min(req.body.yaw || 0, 90)); // J1
    angles[3] = Math.max(-90, Math.min(req.body.pitch || 0, 90)); // J4
    angles[5] = Math.max(-175, Math.min(req.body.roll || 0, 175)); // J6

    // myCobot connected via USB receives instructions from Python
    PythonShell.runString(
      `from pymycobot.mycobot import MyCobot; MyCobot('${ process.env.MY_COBOT_PORT }').send_angles([${ angles }], ${ duration })`,
      null,
      (err) =&gt; err &amp;&amp; console.error(err)
    );
  } catch (err) {
    console.error(err);
  }
  res.send(200);
});

try {
  const angles = [0, 0, 0, 0, 0, 0];

  // Resets posture at startup
  PythonShell.runString(
    `from pymycobot.mycobot import MyCobot; MyCobot('${ process.env.MY_COBOT_PORT }').send_angles([${ angles }], ${ duration })`,
    null,
    (err) =&gt; err &amp;&amp; console.error(err)
  );
} catch(err) {
  console.error(err);
}

http.listen(3000, '0.0.0.0');
</code></pre>
<p dir="auto">Because it's necessary to execute pymycobot through PythonShell, the pymycobot directory must be placed at the same level as app.js.<br />
<a href="https://github.com/elephantrobotics/pymycobot" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/elephantrobotics/pymycobot</a><br />
Once everything is prepared and the PC is connected to myCobot,<br />
you can start the web server and pass the pitch, roll, and yaw values received through POST requests to myCobot.<br />
Although this time the sensor values of AirPods are sent from an iPhone application via POST, the source of the POST could be from anywhere. Therefore, I think setting up such a server could be potentially useful in the future.</p>
<p dir="auto">source code:<br />
<a href="https://github.com/kimizuka/mycobot-express/tree/example/airpods" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/kimizuka/mycobot-express/tree/example/airpods</a></p>
<h2>Summary</h2>
<p dir="auto">This project showcases the integration of headphone motion detection with robotic control, illustrating the potential of combining human movement data with robotics. By capturing head motion through smart headphones and translating it into commands for a robotic arm, it enhances human-robot interaction and introduces innovative applications in automation and assistive technologies. This approach opens up new avenues for intuitive control mechanisms in robotics, making technology more accessible and interactive.<br />
Finally, thanks again to Kimizuka for sharing this case with us.Feel free to explore further or share your insights with us.</p>
]]></description><link>https://community.m5stack.com/topic/6153/echoactions-connecting-thougths-and-robotic-arm-m5stack</link><guid isPermaLink="true">https://community.m5stack.com/topic/6153/echoactions-connecting-thougths-and-robotic-arm-m5stack</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Hand Gestures as the Remote: M5stack-Basic integrated robotic arm]]></title><description><![CDATA[<h2>Introduction</h2>
<p dir="auto">I am a freelancer specializing in machine learning and robotics technology. My passion began during a course in artificial intelligence in college, which inspired me to explore new methods of human-machine interaction. In particular, for the operation of robotic arms, I have always wanted to simplify their complexity to make them more intuitive and easier to use.<br />
The inspiration for this project stems from my love for innovative technology and the pursuit of improving the ways humans interact with machines. My goal is to develop a gesture-based robotic arm control system that allows non-professionals to operate it with ease. For this purpose, I chose Google's MediaPipe library for gesture recognition and used mycobot 320 m5 as the experimental platform.</p>
<h2>Technical Overview</h2>
<h3>Google MediaPipe</h3>
<p dir="auto">MediaPipe is an open-source cross-platform framework developed by Google, specifically designed for building various perception pipelines. This framework offers a wealth of tools and pre-built modules, enabling developers to easily build and deploy complex machine learning models and algorithms, especially in the field of image and video analysis.<br />
<img src="/assets/uploads/files/1705903584795-e88e975d-66a4-4fb1-ae66-a17af9a38989-image.png" alt="0_1705903584530_e88e975d-66a4-4fb1-ae66-a17af9a38989-image.png" class=" img-fluid img-markdown" /><br />
A notable feature of MediaPipe is its support for real-time gesture and facial recognition. It can efficiently process video streams and identify and track human gestures and facial features in real-time. This capability makes it incredibly useful in interactive applications, augmented reality (AR), virtual reality (VR), and robotics.</p>
<p dir="auto">You can try the gesture recognition online feature without needing to install anything.<br />
<a href="https://mediapipe-studio.webapps.google.com/home" target="_blank" rel="noopener noreferrer nofollow ugc">MediaPipe Studio</a><br />
Its easy-to-use API and comprehensive documentation make it easier to integrate this framework, making it very suitable for use in the fields of machine learning and computer vision.</p>
<h3>pymycobot</h3>
<p dir="auto">pymycobot is a Python API for serial communication and control of the mycobot robotic arm. This library is designed to facilitate developers in controlling the mycobot robotic arm using the Python language. It offers a series of functions and commands that allow users to control the movements and behavior of the robotic arm through programming. For example, users can use the library to get the angles of the robotic arm, send angle commands to control the movement of the arm, or get and send the coordinates of the robotic arm.<br />
The only standard for using this library is that it must be used with the mycobot series of robotic arms, which are specifically adapted for the mycobot.</p>
<h2>Product Introduction</h2>
<h3>myCobot 320 M5stack</h3>
<p dir="auto">The myCobot 320 M5 is a six-axis collaborative robotic arm developed by Elephant Robotics for users. It has a working radius of 350mm and a maximum load capacity of 1000g. The robotic arm is suitable for an open ROS simulation development environment and includes forward and inverse kinematics algorithms. It supports multiple programming languages, including Python, C++, Arduino, C#, and JavaScript, and is compatible with Android, Windows, Mac OSX, and Linux platforms. The versatility of the myCobot 320 M5 makes it suitable for a variety of development and integration applications.<img src="/assets/uploads/files/1705903643038-fa0820e5-486e-4975-aa08-f37d18f38009-image.png" alt="0_1705903642794_fa0820e5-486e-4975-aa08-f37d18f38009-image.png" class=" img-fluid img-markdown" /></p>
<h2>2D Camera</h2>
<p dir="auto">A 2D camera that can be mounted on the end of the mycobot320, communicating via a USB data cable. It can present the view seen from the end of the robotic arm.<br />
<img src="/assets/uploads/files/1705903657861-05668d04-0b5d-4509-b48a-e9b735cb2e45-image.png" alt="0_1705903657612_05668d04-0b5d-4509-b48a-e9b735cb2e45-image.png" class=" img-fluid img-markdown" /></p>
<h2>Development Process</h2>
<h3>Project Architecture</h3>
<p dir="auto">I have divided this project primarily into three functional modules:<br />
Gesture Recognition: This module is mainly used for the recognition of gestures, capable of returning information about what the gesture is, such as a thumbs-up, etc.<br />
Robotic Arm Control: This main function is used for setting the motion control of the robotic arm, including coordinate control, angle control, and so on.<br />
Program Logic: This is used to handle the logic of the program's operation, setting confirmation times for gestures, resetting recognition times, etc. These will be detailed further in subsequent sections.<img src="/assets/uploads/files/1705903676515-f030fd21-5f03-4406-b5c2-0cc418f9517e-image.png" alt="0_1705903676298_f030fd21-5f03-4406-b5c2-0cc418f9517e-image.png" class=" img-fluid img-markdown" /></p>
<h2>Compilation Environment</h2>
<p dir="auto">Operating System: Windows 11<br />
Programming Language: Python 3.9+<br />
Libraries:opencv,pymycobot,mediapipe,time</p>
<h2>Gesture Recognition</h2>
<p dir="auto">To perform gesture recognition, we first need to obtain a camera image. Here, we use the OpenCV library to access the camera feed.</p>
<pre><code>
import cv2

# Get camera stream, default camera - 0, external cameras in order - 1, 2, 3
cap = cv2.VideoCapture(1)

# Continuously acquire camera footage
while cap.isOpened():
    #Get the current image screen
    ret, frame = cap.read()
    # Convert BGR image to RGB
    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)    
    # display screen on computer
    cv2.imshow('gesture control',frame)
    # Press the 'q' key to exit to avoid an infinite loop
    if cv2.waitKey(1) &amp; 0xFF == ord('q'):
        break     
</code></pre>
<p dir="auto"><img src="/assets/uploads/files/1705908927203-f6808bb2-e2f7-4c63-9a1a-314c498aa323-image.png" alt="0_1705908925777_f6808bb2-e2f7-4c63-9a1a-314c498aa323-image.png" class=" img-fluid img-markdown" /><br />
With this, the image capture from the camera is successful. Next, we use MediaPipe for gesture recognition.</p>
<pre><code>import mediapipe as mp

# Initialize the MediaPipe Hands module
mp_hands = mp.solutions.hands
hands = mp_hands.Hands()
mp_draw = mp.solutions.drawing_utils


# Process the image and detect hands
result = hands.process(rgb_frame)

if result.multi_hand_landmarks:
    for hand_landmarks in result.multi_hand_landmarks:
        mp_draw.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
</code></pre>
<p dir="auto"><img src="/assets/uploads/files/1705908950913-048861da-f25e-4b6b-8a24-045e6addff45-image.png" alt="0_1705908950612_048861da-f25e-4b6b-8a24-045e6addff45-image.png" class=" img-fluid img-markdown" /><br />
The output after recognizing a gesture is precise in identifying each joint on the hand and names each joint point. MediaPipe Hands provides 21 key points (landmarks) for the hand, collectively depicting the structure of the hand, including the wrist and the joints of each finger. Taking the thumb as an example, there are four joints, which from bottom to top are CMC, MCP, IP, TIP.</p>
<pre><code>cmc: Carpometacarpal Joint
mcp:Metacarpophalangeal Joint
ip:Interphalangeal Joint
tip:tip
</code></pre>
<p dir="auto">Having these landmarks alone is not enough; we need to set a method to recognize specific gestures. For example, if we want to recognize a thumbs-up gesture, we analyze that during a thumbs-up, the tip of the thumb is at the highest point above the entire palm. This makes it much easier. As long as we determine that the tip of the thumb is higher than the tips of all other fingers in the image, then the gesture is identified as a thumbs-up. (Other methods of analysis can also be used.)<br />
Generally, we can obtain three attributes for each joint: X, Y, Z, representing the position of that joint in the image.</p>
<pre><code># Get the attributes of the thumb tip
thump_tip = hand_landmarks.landmark[mp.hands.HandLandmark.THUMB_TIP]

# Get the height of the thumb tip
thump_tip.y

# Determine thumbs up gesture
def is_thump_up(hand_landmarks):
    thumb_tip = hand_landmarks.landmark[mp_hands.HandLandmark.THUMB_TIP]
    index_tip = hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP]
    # Determine which joint is higher.
    if thumb_tip.y &lt; index_tip.y:
        return True
    
    return False
</code></pre>
<p dir="auto">If you want other gestures, you can also set a special identification method based on the characteristics of the hand shape. At this point, gesture recognition is completed.</p>
<h3>Robotic Arm Motion Control</h3>
<p dir="auto">Initially, my idea was that when the camera recognizes a gesture, it would send a control command to the robotic arm. Let's start with a simple action, setting the robotic arm to perform a nodding motion.<br />
The pymycobot library offers many functions that are very convenient for controlling the robotic arm.</p>
<pre><code>from pymycobot.mycobot import Mycobot
import time
# connect robot arm
mc = Mycobot(port,baud)

#Control the movement of the robotic arm using angles
mc.send_angles([angles_list],speed)

#Control the movement of the robotic arm using coordinates
mc.send_coords([coords_list],speed,mode)

# Nodding action
def ThumpUpAction(self):
        self.mc.send_angles([0.96, 86.22, -98.26, 10.54, 86.92, -2.37], 60)
        time.sleep(1.5)
        for count in range(3):
            self.mc.send_angles([0.79, 2.46, (-8.17), 4.3, 88.94, 0.26], 70)
            time.sleep(1)
            self.mc.send_angles([(-3.6), 30.32, (-45.79), (-46.84), 97.38, 0.35], 70)
            time.sleep(1)
        self.mc.send_angles([0.79, 2.46, (-8.17), 4.3, 88.94, 0.26], 70)
        time.sleep(1)
        self.mc.send_angles([0.96, 86.22, -98.26, 10.54, 86.92, -2.37], 60)
</code></pre>
<p dir="auto">To enhance the readability and modifiability of the overall code, it's beneficial to create a robotic arm class for easy calling and modification.</p>
<pre><code>class RobotArmController:

        def __init__(self,port):
        self.mc = MyCobot(port, 115200)
        self.init_pose = [0.96, 86.22, -98.26, 10.54, 86.92, -2.37]
        self.coords = [-40, -92.5, 392.7, -92.19, -1.91, -94.14]
        self.speed = 60
        self.mode = 0
        
        def ThumpUpAction(self):
            ...
            
        def OtherAction(self):
            ...
</code></pre>
<h2>Program Logic Processing</h2>
<p dir="auto">During debugging, some issues arose. When recognizing gestures, continuous recognition meant that if a gesture was recognized 10 times in 1 second, 10 commands would be sent to the robotic arm. This was not what I initially envisioned.<br />
Therefore, logical adjustments were needed. Here's how I addressed it:</p>
<pre><code># Set a 2-second timeframe to confirm the gesture. Only when a thumbs-up gesture is maintained for 2 seconds, the command to control the robotic arm is issued, using a control variable approach.

#init
#Variable to detect whether gesture exists
gesture_detected = False
#Variable that determines the timing after the gesture appears
gesture_start_time = None
# Set the variable 2s after the gesture appears
gesture_confirmation_time = 2

# When a specific gesture appears, gesture_start_time begins to count. During this period, continuous checks are made. If 2 seconds have passed, the gesture is confirmed, and then the corresponding robotic arm movement for that gesture is executed.

current_time = time.time()
if current_gesture:
    if not gesture_detected:
        gesture_detected = True
        gesture_start_time = current_time
    elif current_time - gesture_start_time &gt; gesture_confirmation_time and not action_triggered:
        if current_gesture == "thumb_up":
            robotic arm action()
</code></pre>
<p dir="auto">However, this is still not sufficient, as the hand maintaining the gesture for over 2 seconds would continue sending commands to the robotic arm. Here, we need to set a cooldown period to allow sufficient time for the robotic arm to complete its movement.</p>
<pre><code>action_triggered = False
cooldown_start_time = None
cooldown_period = 2

# process gesture
                current_time = time.time()
                if current_gesture:
                    if not gesture_detected:
                        gesture_detected = True
                        gesture_start_time = current_time
                    elif current_time - gesture_start_time &gt; gesture_confirmation_time and not action_triggered:
                        #Perform corresponding actions based on gestures
                        if current_gesture == "thumb_up":
                            print('good good')
                            mc.thum_up()
                        elif current_gesture == "palm_open":
                            print('forward')
                            mc.increment_x_and_send()
                        # You can add more gestures and corresponding action judgments
                        action_triggered = True
                        cooldown_start_time = current_time
                else:
                    gesture_detected = False
                    gesture_start_time = None
                    if action_triggered and current_time - cooldown_start_time &gt; cooldown_period:
                        print('can continue')
                        action_triggered = False
                        cooldown_start_time = None

</code></pre>
<h2>Video</h2>
<p dir="auto"><a href="https://youtu.be/9vOPKO_IG9M" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/9vOPKO_IG9M</a><br />
Summary<br />
This project demonstrates a method of using gesture recognition to control the myCobot 320, creating a new form of human-machine interaction. Although currently only a limited number of gestures and corresponding robotic arm movements have been implemented, it lays the groundwork for broader applications of robotic arms in the future. The innovative attempt to combine gestures with robotic arm control has not only improved my programming skills but also enhanced my problem-solving abilities, providing valuable experience for future related projects.</p>
]]></description><link>https://community.m5stack.com/topic/6004/hand-gestures-as-the-remote-m5stack-basic-integrated-robotic-arm</link><guid isPermaLink="true">https://community.m5stack.com/topic/6004/hand-gestures-as-the-remote-m5stack-basic-integrated-robotic-arm</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[AI-Enhanced Robotics, GPT-4V and myCobot in Action]]></title><description><![CDATA[<p dir="auto"><em>This article on the mylangrobot project was created by neka-nat, and the author Shirokuma has authorized its editing and reproduction. A big shout out at neka-nat:)<br />
<a href="https://twitter.com/neka_nat" target="_blank" rel="noopener noreferrer nofollow ugc">https://twitter.com/neka_nat</a></em></p>
<p dir="auto"><img src="https://hackster.imgix.net/uploads/attachments/1671536/image_6gzeG2cNR1.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>Introduction</h2>
<p dir="auto">This project demonstrates a simple pick-and-place operation using a robotic arm, employing GPT-4V and myCobot. The demonstration uses a method named SoM (Object Detection Method) to generate robotic movements through natural language. In simpler terms, the machine receives natural language instructions, locates the target, and then commands the robotic arm to perform the grabbing task. The highlight of this project is the combination of GPT-4V's image processing and the SoM object detection algorithm, enabling the robotic arm to move through natural language interaction with the machine.</p>
<h2>Software</h2>
<h3>SoM</h3>
<p dir="auto">Set of Mark (SoM) is a method designed to enhance the visual understanding capabilities of large language models. After an image is processed with SoM, a series of markers are added to it. These markers can be recognized and processed by language models, aiding in more accurate identification and understanding of objects and content within the image. This enhancement allows language models to conduct more precise analysis and descriptions of elements in images, thereby improving their performance in visual tasks.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1671537/_bwKXYoSNej.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>GPT-4V</h3>
<p dir="auto">The commonly discussed GPT is a large predictive model with which we can have conversational interactions. The new iteration, GPT-4V, is a multimodal large language model that not only processes textual information but now also handles image information. It is capable of image understanding, image generation, and image description. This large model combines the powerful natural language processing abilities of GPT-4 with current image analysis technologies, offering more efficient and accurate integrated capabilities in vision and language.<br />
Below is <a href="https://cookbook.openai.com/examples/gpt_with_vision_for_video_understanding" target="_blank" rel="noopener noreferrer nofollow ugc">an example provided by OpenAI:</a></p>
<pre><code>User:
"These are frames from a video that I want to upload. Generate a compelling description that I can upload along with the video."
</code></pre>
<p dir="auto"><img src="https://hackster.imgix.net/uploads/attachments/1671538/image_ImW1wSoFMn.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<pre><code>#GPT-4V Image description processing
GPT4:
"🐺 Survival of the Fittest: An Epic Tale in the Snow ❄️ - Witness the intense drama of nature as a pack of wolves face off against mighty bison in a harsh winter landscape. This raw footage captures the essence of the wild where every creature fights for survival. With each frame, experience the tension, the strategy, and the sheer force exerted in this life-or-death struggle. See nature's true colors in this gripping encounter on the snowy plains. 🦬"

Remember to respect wildlife and nature. This video may contain scenes that some viewers might find intense or distressing, but they depict natural animal behaviors important for ecological studies and understanding the reality of life in the wilderness.
</code></pre>
<h3>Openai-whisper</h3>
<p dir="auto"><a href="https://openai.com/research/whisper" target="_blank" rel="noopener noreferrer nofollow ugc">https://openai.com/research/whisper</a><br />
An automatic speech recognition (ASR) system developed by OpenAI. It utilizes advanced deep learning techniques to transcribe, translate, and understand human speech. Whisper is characterized by its ability to support multiple languages and its exceptional performance in recognizing voices with various accents and in noisy environments. Additionally, it can handle different audio qualities, making it suitable for various applications such as transcribing meeting records, automatically generating subtitles, and assisting in translations.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1671539/image_hRNiVtcWKF.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>pymycobot</h3>
<p dir="auto"><a href="https://github.com/elephantrobotics/pymycobot/" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/elephantrobotics/pymycobot/</a><br />
pymycobot is a Python library for the mycobot robot series. MyCobot is a compact, multifunctional collaborative robotic arm suitable for education, research, and lightweight industrial applications. The PyMyCobot library provides a simple programming interface, enabling developers to control and program MyCobot robots for operations such as movement, grabbing, and sensing. This library supports multiple operating systems and development environments, facilitating its integration into various projects, especially in robotics and automation. By using Python, a widely-used programming language, pymycobot makes operating and experimenting with MyCobot robots more accessible and flexible.</p>
<h2>Hardware</h2>
<h3>myCobot 280M5</h3>
<p dir="auto">The myCobot 280 M5 is a desktop-level compact six-axis collaborative robot produced by Elephant Robotics. Designed for compactness, it is suitable for education, research, and light industrial applications. The myCobot 280 M5 supports various programming and control methods, compatible with different operating systems and programming languages, including:<br />
●Main and auxiliary control chips: ESP32<br />
●Supports Bluetooth (2.4G/5G) and wireless (2.4G 3D Antenna)<br />
●Multiple input and output ports<br />
●Supports free movement, joint movement, Cartesian movement, trajectory recording, and wireless control<br />
●Compatible operating systems: Windows, Linux, MAC<br />
●Supported programming languages: Python, C++, C#, JavaScript<br />
●Supported programming platforms and tools: RoboFlow, myblockly, Mind+, UiFlow, Arduino, mystudio<br />
●Supported communication protocols: Serial port control protocol, TCP/IP, MODBUS<br />
These features make the myCobot 280 M5 a versatile, user-friendly robot solution suitable for a variety of application scenarios.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1671541/_jrCeeyf5SM.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>myCobot Vertical Suction Pump V2.0</h3>
<p dir="auto">Operates on the principle of vacuum adhesion, providing 3.3V IO control, and can be extensively used in the development of various embedded devices.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1671545/image_95m3eTMvvl.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>Camera</h3>
<p dir="auto">Standard USB and LEGO interfaces. The USB interface can be used with various PC devices, and the LEGO interface can be conveniently fixed. It is applicable to machine vision, image recognition, and other applications.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1671547/image_Vsk67uhSCo.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
mylangrobot Software Analysis<br />
The specific workflow of the project described at the beginning is as follows:</p>
<ol>
<li>Audio Input: Record audio instructions first.</li>
<li>Audio Processing: Use "openai-whisper" to process the audio and convert it into text.</li>
<li>Language Model Interaction: Use the GPT-4 model to process the converted text instructions and understand the user's commands.</li>
<li>Image Processing: Use GPT-4V and the enhanced image capability of SoM to process images and find the target mentioned in the instructions.</li>
<li>Robotic Arm Control: Control the robotic arm to grab the identified target.</li>
</ol>
<p dir="auto">Audio Processing<br />
This function utilizes speech_recognition to capture audio data from the microphone, enabling the computer to recognize it.<br />
Libraries used:</p>
<pre><code>import io
import os
from enum import Enum
from typing import Protocol

import openai
import speech_recognition as sr
from pydub import AudioSegment
from pydub.playback import play
</code></pre>
<p dir="auto">Define interfaces, capture user input, and provide output to the user.</p>
<pre><code>class Interface(Protocol):
    def input(self, prefix: str = "") -&gt; str:
        return prefix + self._input_impl()

    def _input_impl(self) -&gt; str:
        ...

    def output(self, message: str) -&gt; None:
        ...
</code></pre>
<p dir="auto">Initialize the microphone for audio input and output.</p>
<pre><code>class Audio(Interface):
    def __init__(self):
        self.r = sr.Recognizer()
        self.mic = sr.Microphone()
        # openai-whisper API key
        self.client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
</code></pre>
<p dir="auto">Convert the input audio into text format for output.</p>
<pre><code> def _input_impl(self) -&gt; str:
        print("Please tell me your command.")
        with self.mic as source:
            self.r.adjust_for_ambient_noise(source)
            audio = self.r.listen(source)

        try:
            return self.r.recognize_whisper(audio, language="japanese")

        except sr.UnknownValueError:
            print("could not understand audio")
        except sr.RequestError as e:
            print("Could not request results from Google Speech Recognition service; {0}".format(e))
</code></pre>
<p dir="auto">The final return 'r' is the text format of the audio, which can be used for interaction with the GPT-4 model.</p>
<h3>Image Processing and GPT-4 Language Interaction</h3>
<p dir="auto">When transmitting text to the GPT-4 model for interaction, images are sent along, so image processing and interaction are discussed together.<br />
Libraries used for image processing:</p>
<pre><code>import cv2
import numpy as np
import supervision as sv
import torch
from segment_anything import SamAutomaticMaskGenerator, sam_model_registry

from .utils import download_sam_model_to_cache
</code></pre>
<p dir="auto">Primarily uses the SamAutomaticMaskGenerator feature to mark and draw markers on detected targets.</p>
<pre><code>#Convert image to RGB format
        image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
#Image processing, target detection and marker rendering
        sam_result = self.mask_generator.generate(image_rgb)
        detections = sv.Detections.from_sam(sam_result=sam_result)
        height, width, _ = image.shape
        image_area = height * width

        min_area_mask = (detections.area / image_area) &gt; self.MIN_AREA_PERCENTAGE
        max_area_mask = (detections.area / image_area) &lt; self.MAX_AREA_PERCENTAGE
        detections = detections[min_area_mask &amp; max_area_mask]
        
        
        #Returns the result of the image and detected information
        labels = [str(i) for i in range(len(detections))]
        annotated_image = mask_annotator.annotate(scene=image_rgb.copy(), detections=detections)
        annotated_image = label_annotator.annotate(scene=annotated_image, detections=detections, labels=labels)
        return annotated_image, detections

</code></pre>
<p dir="auto"><img src="https://hackster.imgix.net/uploads/attachments/1671548/image_aiT6dtqGse.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
<img src="https://hackster.imgix.net/uploads/attachments/1671549/image_j8UHTvji8R.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
This results in the following effect.<br />
Note: The below function requires obtaining the GPT-4 API-Key for usage.<br />
The resulting image is passed to the GPT-4 model, which requires some processing before use. Through GPT-4V, the image can be processed to return information about the image content and corresponding object information.</p>
<pre><code>def prepare_inputs(message: str, image: np.ndarray) -&gt; dict:
    # # Path to your image
    # image_path = "temp.jpg"
    # # Getting the base64 string
    base64_image = encode_image_from_cv2(image)

    payload = {
        "model": "gpt-4-vision-preview",
        "messages": [
            {"role": "system", "content": [metaprompt]},
            {
                "role": "user",
                "content": [
                    {
                        "type": "text",
                        "text": message,
                    },
                    {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}},
                ],
            },
        ],
        "max_tokens": 800,
    }

    return payload


def request_gpt4v(message: str, image: np.ndarray) -&gt; str:
    payload = prepare_inputs(message, image)
    response = requests.post("https://api.openai.com/v1/chat/completions", headers=headers, json=payload)
    res = response.json()["choices"][0]["message"]["content"]
    return res
</code></pre>
<p dir="auto">Robotic Arm Control and Overall Integration<br />
After image processing and GPT-4V model processing, the interpreted instructions generate target position information. This position information is passed to the robotic arm control system, which moves to the corresponding location to perform the grabbing action.<br />
Key methods involved:<br />
Move to the target object.</p>
<pre><code>    def move_to_object(self, object_no: int, speed: Optional[float] = None) -&gt; None:
        object_no = self._check_and_correct_object_no(object_no)
        print("[MyCobotController] Move to Object No. {}".format(object_no))
        detection = (
            np.array([-self._detections[object_no][0], -self._detections[object_no][1&rsqb;&rsqb;) + self.capture_coord.pos[:2]
        )
        print("[MyCobotController] Object pos:", detection[0], detection[1])
        self.move_to_xy(detection[0], detection[1], speed)
</code></pre>
<pre><code>grab action
  def grab(self, speed: Optional[float] = None) -&gt; None:
        print("[MyCobotController] Grab to Object")
        current_pos = self.current_coords().pos
        self.move_to_z(self.object_height + self.end_effector_height, speed)
        self._mycobot.set_basic_output(self._suction_pin, 0)
        time.sleep(2)
        self.move_to_z(current_pos[2], speed)

drop action
    def move_to_place(self, place_name: str, speed: Optional[float] = None) -&gt; None:
        print("[MyCobotController] Move to Place {}".format(place_name))
        self._current_position = self.positions[place_name]
        self._mycobot.sync_send_angles(
            np.array(self._current_position) + self.calc_gravity_compensation(self._current_position),
            speed or self._default_speed,
            self._command_timeout,
        )
        print("Current coords: {}".format(self.current_coords()))
</code></pre>
<p dir="auto">After each function is implemented, coordinate the entire process, streamline the workflow logic, and complete the task.<br />
The specific code can be viewed in the <a href="http://operator.py" target="_blank" rel="noopener noreferrer nofollow ugc">operator.py</a> file.</p>
<h2>Example</h2>
<p dir="auto">Below is an example test to observe the project's outcome. The content involves a voice input saying "pick up the chocolate," and the robotic arm executes the task.<br />
<a href="https://youtu.be/Eda1m7DnIhQ" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/Eda1m7DnIhQ</a></p>
<h2>Summary</h2>
<p dir="auto">This project demonstrates how to leverage advanced artificial intelligence and robotics technologies to accomplish complex automation tasks. By integrating voice recognition, natural language processing, image analysis, and precise robotic arm control, the project has successfully created a robotic system capable of understanding and executing spoken instructions. This not only enhances the naturalness and efficiency of robot-human interaction but also opens up new possibilities for robotic technology in various practical applications, such as automated manufacturing, logistics, assistive robots, and more.<br />
Finally, thanks again to Shirokuma for sharing this case with us. If you have better examples, feel free to contact us!</p>
]]></description><link>https://community.m5stack.com/topic/5970/ai-enhanced-robotics-gpt-4v-and-mycobot-in-action</link><guid isPermaLink="true">https://community.m5stack.com/topic/5970/ai-enhanced-robotics-gpt-4v-and-mycobot-in-action</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Creating a Synchronized Robotic Arm Demo: Step-by-Step Guide]]></title><description><![CDATA[<h2>Introduction</h2>
<p dir="auto">Today, I am going to present a robotic arm model that I have independently designed and implemented. The core feature of this model is to achieve real-time gesture tracking - just a gentle drag with your hand, and the robotic arm can immediately follow your movements.</p>
<p dir="auto">The reason why I wanted to create such a model is that in some dangerous environments, we can use robotic arms to replace manual work, thereby avoiding threats to human life.</p>
<p dir="auto">You might ask, why not directly use remote keyboard control, joystick control, or APP control, but choose to manually drag? I believe that only manual operation can satisfy our need for precision to the greatest extent. Therefore, I decided to start trying to make this model and have initially completed the entire demo.</p>
<p dir="auto">I hope that through this demo, I can demonstrate the infinite possibilities of robotic arms to everyone, and at the same time, I hope to inspire everyone's infinite longing for future technology.</p>
<h2>Robotic Arm</h2>
<p dir="auto">The mechArm 270 is a 6 DOF robotic arm, with a compact structure design that can fit into a backpack for easy transportation. Importantly, it has many open control APIs, which allows you to quickly start controlling the robotic arm using Python. There are no complicated operations, and it even supports graphical programming, which allows people who are not very familiar with code to quickly get started with controlling the robotic arm.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1644514/_8bvUAicseK.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
The mechArm is a desktop robotic arm with a structure that mimics industrial designs. Its maximum working radius is 270mm, it can carry a load of 250g, and its repeat positioning accuracy is controlled within ±0.5mm.</p>
<h2>Project</h2>
<p dir="auto">After introducing the basic equipment, let's start with the record of how I created this demo.</p>
<p dir="auto">Environment:<br />
Operating system: Windows 11</p>
<p dir="auto">Programming language: Python 3.9+</p>
<p dir="auto">Python libraries: pymycobot, time</p>
<p dir="auto">pymycobot is an open-source library for Elephant Robotics, specifically designed to control the robotic arm of Elephant Robotics. Here is an example of a simple control code.</p>
<p dir="auto">Code：</p>
<pre><code>#Main methods used

#Create objects to communicate with the robotic arm.
MyCobot(serial,baud)
# angles control robot,
send_angles([list_angles],speed)
# coords control robot
send_coords([list_coords],speed,mode)

Example:

import time
from pymycobot.mycobot import MyCobot

# create a object
mc = MyCobot("com7",115200)

# angles control
mc.send_angles([0,0,0,0,0,0],100)
time.sleep(1)
mc.send_angles([90,90,90,90,90,90],100)
time.sleep(1)
</code></pre>
<p dir="auto">I briefly introduced how to use python to control mechArm. Isn’t it easy?</p>
<h2>Problem Analysis</h2>
<p dir="auto">Before starting the project, it's important to set up a framework and understand the specific problems we need to solve. For this, I made a flowchart of the project. In the following, I will refer to the manually controlled robotic arm as R1, and the following motion robotic arm as R2.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1644515/_Glx8vYpjQD.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Control Robotic Arm: As mentioned above, the robotic arm can be controlled using the methods provided by the pymycobot library.</p>
<p dir="auto">Motion Control Methods: The R1 robotic arm can be dragged by hand, returning the current angle information of the robotic arm at all times. The R2 robotic arm controls based on the angle information received from R1.</p>
<p dir="auto">Communication Between Robotic Arms: This step is quite important in the entire project. Once established, the robotic arm can easily implement information transmission.</p>
<p dir="auto">Next, I will mainly explain the Motion Control Methods and Communication Between Robotic Arms.</p>
<h2>Motion Control methods</h2>
<ol>
<li>Get real-time angle information</li>
</ol>
<p dir="auto">pymycobot provides the "get_angles()" method to obtain the angle information of the current robot arm.</p>
<pre><code># Can obtain the current angle information of the robotic arm in real time
get_angles()

# example
print("real-time angles:",mc.get_anlges())

result: real-time angles:[0,0,0,0,0,0]

# Continuously obtain the current angle
while True:
    angels = mc.get_angles()
    print(angles) 
    time.sleep(0.1) #Go to the next step every 0.1s
</code></pre>
<ol start="2">
<li>Set the Refresh Mode for the Robotic Arm</li>
</ol>
<p dir="auto">The refresh mode of the robotic arm mainly falls into two categories: interpolation mode and non-interpolation mode. These refer to the ways in which the end effector of the robotic arm is controlled during motion trajectory planning. If no mode is set, the robotic arm may not be able to perform the expected motion correctly, which may lead to the following consequences:</p>
<ol>
<li>
<p dir="auto">Unsmooth motion</p>
</li>
<li>
<p dir="auto">Inaccurate motion</p>
</li>
<li>
<p dir="auto">Discontinuous motion</p>
</li>
</ol>
<p dir="auto">Interpolation Mode: The interpolation mode can realize smooth and continuous trajectory planning, ensuring that the position and posture of the end effector of the robotic arm transition smoothly during the motion process.</p>
<p dir="auto">Non-Interpolation Mode: The non-interpolation mode means that the robotic arm only focuses on specific target points during the motion process, without performing interpolation calculations. Under the non-interpolation mode, the position and posture of the robotic arm will jump directly between key points, without undergoing a smooth transition.</p>
<p dir="auto">When multiple robotic arms use the interpolation mode for motion at the same time, there may be situations of waiting or queuing. Therefore, we choose to use the non-interpolation mode.</p>
<pre><code>#Set refresh mode
set_fresh_mode(1/0) 
1：no interpolation
0：interpolation

mc.set_fresh_mode(1)
</code></pre>
<p dir="auto">Our code that integrates the previous ones is as follows.</p>
<p dir="auto">Code:</p>
<pre><code>import time
from pymycobot.mycobot import MyCobot

mc = MyCobot("COM7", 115200)    #release arm
mb = MyCobot("COM11", 115200)   #move arm

mb.set_fresh_mode(1)    #no interpolation
time.sleep(1)
mc.release_all_servos() #release robot
time.sleep(1)
speed = 100
while True:
    angles = mc.get_angles()    #get release arm angles
    mb.send_angles(angles, speed)   #send angles to move arm
    time.sleep(0.1)
## Communication between robotic arms：
Our solution is to connect two robotic arms to the same PC and connect them through a serial port.

# build connection
from pymycobot.mycobot import MyCobot

mc = MyCobot("COM7", 115200)   
mb = MyCobot("COM11", 115200)
</code></pre>
<p dir="auto">By using the most basic USB data cables for connection, we have two serial port numbers for the robotic arms on our computer, and we can send instructions to them separately.<br />
<img src="/assets/uploads/files/1699432440269-%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20231108163344.png" alt="0_1699432439569_微信图片_20231108163344.png" class=" img-fluid img-markdown" /><br />
<a href="https://www.youtube.com/watch?v=NByjgoqc2O4" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.youtube.com/watch?v=NByjgoqc2O4</a></p>
<h2>Summary</h2>
<p dir="auto">From the content, it can be seen that although we can achieve about 70-80% synchronization, there are other factors that can cause significant delays. The reasons for the delays could be various, such as the speed of data processing and transmission, the reaction speed of the robotic arm, software optimization, hardware performance, etc. All of these are potential factors that can cause delays.</p>
<p dir="auto">In addition, there is a significant limitation in that their communication is connected through serial ports. If the distance is a bit further, this method cannot be used, and its practicality is not strong. In the future, I will try to use wireless connections such as Bluetooth and WiFi to control the robotic arm.</p>
]]></description><link>https://community.m5stack.com/topic/5785/creating-a-synchronized-robotic-arm-demo-step-by-step-guide</link><guid isPermaLink="true">https://community.m5stack.com/topic/5785/creating-a-synchronized-robotic-arm-demo-step-by-step-guide</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Controlling myCobot 320 with MyCobot Controller App]]></title><description><![CDATA[<h2>Introduction</h2>
<p dir="auto">Robotic arms are essential tools in modern industry and research fields, with widespread applications in manufacturing, healthcare, agriculture, education, and more. These robotic arms can not only perform precise operations but also work in hazardous environments inaccessible to humans, greatly enhancing work efficiency and safety.However, traditional control methods of robotic arms often require specialized knowledge and complex programming, which to some extent limits their popularization and application. Therefore, the method of controlling robotic arms via mobile apps emerged. The advantage of mobile app control is that it allows non-professionals to conveniently operate robotic arms. Moreover, through the mobile app, users can remotely control the robotic arm, greatly improving the convenience and flexibility of operation.This article aims to delve into the topic of how to use a mobile app to control robotic arms.</p>
<h2>Product</h2>
<h2>myCobot 320</h2>
<p dir="auto">The myCobot 320 is a 6-axis collaborative robotic arm designed for user-oriented programming and development. It has built-in forward and inverse kinematics algorithms, offers an open ROS simulation development environment, and comes equipped with 12 standard 24V industrial IO interfaces, which can be expanded for PLC control programming. The working radius of the myCobot 320 can reach up to 350mm, and the end can bear a maximum load of <a href="http://1kg.It" target="_blank" rel="noopener noreferrer nofollow ugc">1kg.It</a> offers precise positioning repeatability within a range of 0.5mm.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640317/image_cNj0nvLvpB.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
myCobot Controller<br />
The "myCobot Controller" is an application launched by Elephant Robotics specifically for controlling the myCobot series of robotic arms. This app employs Bluetooth technology, enabling wireless connection between the user's smartphone or tablet and the myCobot robotic arm.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640318/image_KXYeA0wNlY.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
The working principle of the myCobot Controller APP is mainly based on Bluetooth communication technology. After successfully pairing with the myCobot robotic arm via Bluetooth, the app can control various functions of the robotic arm. This method is not only easy to operate, but it also allows for real-time, wireless control, greatly enhancing the flexibility and convenience of operation.</p>
<p dir="auto">Steps for APP to control myCobot<br />
Next, we will introduce how to use this function while operating.</p>
<h2>Install APP</h2>
<p dir="auto">Currently, the myCobot Controller only supports Android system phones, and IOS system users will need to wait for some time. Clicking connect can directly lead to the download location.Currently, there are two ways to install the app. The first one is to directly search for "myCobot controller" on the Google Play Store for download.The second one is to download the APK directly from the official website to the mobile phone for installation. (You can install it directly after a normal download).<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640319/image_heQIimwLLr.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>Connect myCobot</h2>
<p dir="auto">First, we power up the myCobot and select "Transponder".<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640320/_X8ESzlzOH0.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
After entering, we choose the Bluetooth mode, "Bluetooth".<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640321/_Eh04sZcde9.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
After successful operation, the interface will appear as shown in the following image. The name of the Bluetooth is: mycobot320m5ble, and its MAC address is: 08:3a:f2:42:f0:26 (Each machine is different, which is convenient for distinguishing when two machines are on at the same time). Upon accessing this page, we simply need to wait, as the subsequent steps can be performed on a mobile phone.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640322/_sqRGXt4aUv.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Open the downloaded APP, click the Bluetooth icon to connect to myCobot.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640323/_7WyVMRVF5T.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Make sure the name of the Bluetooth corresponds to the name of the robotic arm, "mycobot320m5ble". If you are uncertain, you can verify the MAC address due to its uniqueness. If the display is as shown in the following image, the connection is successful.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640324/_rtPfSkePd8.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>Robotic arm motion control</h2>
<p dir="auto">The APP controls the robotic arm using forward and inverse kinematics, mainly in two ways: one is the control of the robotic arm's angle, and the other is the control of the robotic arm's coordinates.</p>
<h2>Joint Control</h2>
<p dir="auto">Joint control is a control method of the forward kinematics algorithm. Forward kinematics refers to the process of calculating the position and posture of the robot's end effector when the parameters (Joint) of each joint of the robot are known. In other words, the spatial coordinates of the end of the robotic arm can be calculated by rotating the angles.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640325/image_uETogXcaJA.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
The Joint (1-6) on both sides can be increased or decreased to control the corresponding myCobot joint angles. The six parameters in the middle TCL part represent the Cartesian coordinate values of the robotic arm's end at this moment.</p>
<h2>Coords Control</h2>
<p dir="auto">Coordinate control is a control method of the inverse kinematics algorithm. Inverse kinematics refers to the process of calculating the parameters (angles) of each joint of the robot when the coordinate position of the robot's end effector is known. This allows the robot to be moved by adjusting the coordinates of the robot's end, thereby calculating the parameters of the robot's joint angles under the current state.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1640326/image_bKd0Z1V2wa.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
The buttons on the left are easy to understand, corresponding to the position of the robotic arm's end in space, moving linearly up, down, left, and right. In other words, the end of the robotic arm moves forward, backward, left, right, up, and down in space, mainly in straight line movements. In Cartesian coordinates, 'Rz, Ry, Rx' are usually used to represent rotations around the z-axis, y-axis, and x-axis. These rotations typically follow the right-hand rule, that is, if your right hand's four fingers curl in the direction of rotation, then the direction your thumb points is the direction of the rotation axis.</p>
<p dir="auto">Generally speaking:</p>
<p dir="auto">● "rz": rotation around the z-axis. This will cause the end of the robotic arm to rotate within the x-y plane, that is, it will change the yaw angle of the end effector.</p>
<p dir="auto">● "ry": rotation around the y-axis. This will cause the end of the robotic arm to rotate within the z-x plane, that is, it will change the pitch angle of the end effector.</p>
<p dir="auto">● "rx": rotation around the x-axis. This will cause the end of the robotic arm to rotate within the y-z plane, that is, it will change the roll angle of the end effector.</p>
<p dir="auto">In simpler terms, it is the robotic arm rotating around the x, y, z axes.</p>
<h2>Operation video</h2>
<p dir="auto"><a href="https://youtu.be/8JBhk55pz8I" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/8JBhk55pz8I</a></p>
<h2>Summary</h2>
<p dir="auto">Overall, the mobile app control provides a more intuitive and easier-to-understand operating method, allowing non-professionals to quickly get started. In addition, we can remotely control the robotic arm, which makes it possible to operate the robotic arm in some complex or dangerous environments, thus expanding the application scenarios of the robotic arm.</p>
<p dir="auto">Currently, the functionality of the app can still be expanded. What features do you think need to be added to the app? Feel free to comment below, let's discuss the optimization of the app's functionality together! If you like this article, likes and comments are the greatest support for us!</p>
]]></description><link>https://community.m5stack.com/topic/5755/controlling-mycobot-320-with-mycobot-controller-app</link><guid isPermaLink="true">https://community.m5stack.com/topic/5755/controlling-mycobot-320-with-mycobot-controller-app</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Harnessing the Power of ROS and MoveIt in Robotic Arm Manipulation]]></title><description><![CDATA[<h2>Introduction</h2>
<p dir="auto">This article will document my experience using myCobot 280 M5stack in ROS. Why use ROS? Because when it comes to robotics, it's hard to avoid the ROS operating system.<br />
Today is our first time using this system. Today, I will start with an introduction to ROS, the configuration of the environment, and the use of mycobot280 in ROS.</p>
<h2>ROS</h2>
<p dir="auto">ROS (Robot Operating System) is a flexible framework for writing robot software. It is a semi-open source project that provides researchers and developers with a set of tools and libraries to help them create various robot applications. ROS is mainly used for research and development of various robot systems, such as autonomous vehicles, service robots, industrial robots, drones, etc. It makes the development of robots more efficient and enhances the functionality and flexibility of robots. The two most notable modules in the ROS operating system are navigation and robotic arm control (moveit). Moveit allows users to quickly build robotic arm models and implement robotic arm control, such as modeling, kinematic solution, motion planning, obstacle avoidance, and more. Given such a powerful system, I want to use it to simulate some functions of the robotic arm, such as obstacle avoidance, path planning, etc.<br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/e/9/e97ac6f06d51ef35cc4eb851b239108eed920b47.png" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>Environment configuration</h2>
<p dir="auto">ROS primarily supports operating systems like Ubuntu (Linux) and Mac OS (with partial support). The most common usage is on the Ubuntu system. My computer is installed with Ubuntu 18.04 version. The corresponding ROS version for Ubuntu 18 is Melodic. Different versions of Ubuntu correspond to different ROS versions.</p>
<pre><code>ubuntu16.04-kinetic
ubuntu18.04-melodic
ubuntu20.04-noetic
</code></pre>
<p dir="auto">Since my computer has already had the system and ROS environment installed, I won’t record each step here. The main focus will be on the operations within ROS. For the installation of the Ubuntu system and the setup of the ROS environment, you can search on Google. The ROS official website also has detailed installation tutorials.<br />
The scenario I’m using today involves controlling a robotic arm with MoveIt, so the demand for computer hardware is not high. Please note that if you are using features like SLAM radar navigation, you might need a higher-spec computer to handle the computational power. The standard to check whether ROS has been successfully installed is to open the terminal and type “roscore”. If the content that appears is the same as the image below, it means the installation was successful.<br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/8/f/8ff4cf94f5fd258d418565c044be3c87cb07c988.png" alt="alt text" class=" img-fluid img-markdown" /><br />
Let’s use the ROS!</p>
<h2>Project</h2>
<p dir="auto">To create a robotic arm in ROS and use some path planning features, you need to perform the following steps:</p>
<ul>
<li>
<p dir="auto">list itemCreate a URDF file, which is the model of the robotic arm.</p>
</li>
<li>
<p dir="auto">list itemLoad the URDF file into the ROS server.</p>
</li>
<li>
<p dir="auto">list itemUse RViz for visualization.</p>
</li>
<li>
<p dir="auto">list itemCreate a MoveIt configuration package.</p>
</li>
<li>
<p dir="auto">list itemUse MoveIt for motion planning.</p>
</li>
</ul>
<h3>Creating a URDF file</h3>
<p dir="auto">Creating a URDF file First, we need to create a URDF (Unified Robot Description Format) file for the robotic arm. This file is crucial as it describes the properties of the robotic arm, such as joints, links, and sensors, in the form of a 3D model. Since the product is the myCobot 280 M5Stack robotic arm from Elephant Robotics, Elephant Robotics has provided a URDF file for the myCobot 280 on Github, which describes some physical properties of the robotic arm.<br />
<strong>How to generate a URDF file:</strong><br />
You need to use CAD software to create the model, ensuring that the 3D model you create matches the actual size of the robotic arm. Because the exported model needs to be in a format that ROS can accept, it is usually a DAE (Collada) file.<br />
<img src="https://community.robotshop.com/forum/uploads/default/optimized/3X/b/b/bb1e983714caf20cb9f849f5cb42a225cc70b966_2_132x230.png" alt="alt text" class=" img-fluid img-markdown" /><br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/6/8/68d5ea40ef82c5aa920c0970dd514484d1e5a0c6.png" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>Load URDF to ROS server</h3>
<p dir="auto"><strong>Create a ROS package</strong><br />
To create a package to store the URDF file, execute the following code in the terminal:</p>
<pre><code>catkin_create_pkg mycobot_description rospy std_msgs sensor_msgs
</code></pre>
<p dir="auto">Here, ‘rospy’, ‘std_msgs’, and ‘sensor_msgs’ are dependency packages in ROS. Add the generated URDF file to the mycobot_description/urdf directory.</p>
<p dir="auto"><strong>Create a launch file</strong><br />
In the mycobot_description/launch directory, create a file named load_urdf.launch and add the following content to it.</p>
<pre><code>&lt;launch&gt;  &lt;param name="robot_description" command="$(find xacro)/xacro.py $(find mycobot_description)/urdf/mycobot.urdf.xacro" /&gt;&lt;/launch&gt;
</code></pre>
<p dir="auto"><strong>Lanuch ROS file</strong><br />
Open the terminal and enter the following command:</p>
<pre><code>roslaunch my_robot_description load_urdf.launch
</code></pre>
<p dir="auto">After running, we can see the model we created in RViz.<br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/1/4/14382b10b51a7b9fc990a15de195dad00d0fb271.png" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>Configure MoveIt</h2>
<p dir="auto">Start MoveIt Setup Assistant:</p>
<p dir="auto">In a terminal, run the following command to start MoveIt Setup Assistant:</p>
<pre><code>roslaunch moveit_setup_assistant setup_assistant.launch
</code></pre>
<p dir="auto"><img src="https://community.robotshop.com/forum/uploads/default/original/3X/3/2/324920697c3a5020b017261cc3c11257f408f015.png" alt="alt text" class=" img-fluid img-markdown" /><br />
Load URDF in MoveIt In the main interface of MoveIt Setup Assistant, click the “Create New MoveIt Configuration Package” button. Then, in the pop-up dialogue box, select my URDF file (in the ROS parameter robot_description). Click the “Load Files” button to load your URDF file. If the image as shown below appears, it means the file has been loaded successfully.<br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/a/d/ad048036c1f67ce310cf95cdbae162682e7bb202.png" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>Configure Robot</h2>
<p dir="auto">Configure your robot according to your needs. Here are a few configurations briefly introduced:</p>
<ul>
<li>Self-Collisions: MoveIt will automatically calculate the self-collision matrix of your robot. You can<br />
click the “Regenerate Default Collision Matrix” button to generate a default self-collision matrix.</li>
<li>Virtual Joints: You can define virtual joints for your robot. Virtual joints are often used to connect your robot to the world.</li>
<li>Planning Groups: You can define the planning groups of your robot. Planning groups are a set of joints and links that need to move together. For example, you can create a planning group that includes all arm joints.</li>
<li>Robot Poses: You can define preset poses for your robot. These preset poses can be reused in planning.</li>
</ul>
<p dir="auto">After the configuration is completed, a .launch file will be generated, and we can use the robotic arm in moveit by running it.<br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/8/f/8f484e96903b260c9056f27f3d17f3294a721b22.png" alt="alt text" class=" img-fluid img-markdown" /><br />
Let’s see how the moveit function performs path planning. By dragging the coordinates of the end of the robotic arm, we can make changes to the movement of the robotic arm, and also randomly generate paths.<br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/a/2/a2f8cb4d6678f2824942cc3b7a557c23cea30434.gif" alt="alt text" class=" img-fluid img-markdown" /><br />
<strong>Object obstacle avoidance</strong></p>
<p dir="auto">We add an obstacle in MoveIt for the robotic arm to avoid. We add a cube, so the robotic arm will navigate around it when it follows its trajectory.<br />
<img src="https://community.robotshop.com/forum/uploads/default/original/3X/a/5/a56b9dba256588bb104e91fca64e5e941bb6df94.gif" alt="alt text" class=" img-fluid img-markdown" /><br />
In addition to this, MoveIt has many features. For instance, motion planning, which can perform path planning for multi-joint robots, avoid collisions, and also use various motion planning algorithms like RRT, EST, LBKPIECE, etc. It also includes collision detection, which can carry out complex 3D collision detection, including self-collision and environmental collision (obstacles). Furthermore, it offers simulation capabilities, and can be integrated with the Gazebo robot simulator for realistic physical simulation, among other features.</p>
<h2>Summary</h2>
<p dir="auto">MoveIt provides a comprehensive set of tools for research into the motion planning and control of robotic arms, eliminating the need to build complex motion planning systems from scratch. This allows developers to focus more of their energy on implementing specific application functions, rather than on solving underlying motion planning and control problems. Overall, ROS and MoveIt provide strong support for the development of robotic technology. They not only reduce development difficulties and improve development efficiency, but also promote innovation and application in robotic technology. Whether you are a researcher in robotic technology or a developer in practical applications, ROS and MoveIt will be indispensable tools for you.</p>
<p dir="auto">In the future, I will continue to explore more robotic arm projects and share my findings and achievements from time to time. If you find any errors in this article, feel free to communicate with me. If you like this article, your likes and comments will be the greatest support for me!</p>
]]></description><link>https://community.m5stack.com/topic/5650/harnessing-the-power-of-ros-and-moveit-in-robotic-arm-manipulation</link><guid isPermaLink="true">https://community.m5stack.com/topic/5650/harnessing-the-power-of-ros-and-moveit-in-robotic-arm-manipulation</guid><dc:creator><![CDATA[Yuly12]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Revealing the Potential of myCobotM5Stack AI Kit Vision Algorithms]]></title><description><![CDATA[<h2>Introduction</h2>
<p dir="auto">In this article, we will delve deeper into understanding how the machine recognition algorithm of myCobot 320 AI Kit is implemented. In today's society, with the continuous development of artificial intelligence technology, the application of robotic arms is becoming increasingly widespread. As a robot that can simulate human arm movements, the robotic arm has a series of advantages such as efficiency, precision, flexibility, and safety. In industrial, logistics, medical, agricultural and other fields, robotic arms have become an essential part of many automated production lines and systems. For example, in scenes such as automated assembly on factory production lines, cargo handling in warehouse logistics, auxiliary operations in medical surgery, and planting and harvesting in agricultural production, robotic arms can play its unique role. This article will focus on introducing the application of robotic arms combined with vision recognition technology in the myCobot 320 AI Kit scene, and exploring the advantages and future development trends of robotic arm vision control technology.</p>
<h2>Product</h2>
<h3>myCobot 320 M5Stack</h3>
<p dir="auto"><a href="https://shop.elephantrobotics.com/en-hk/collections/mycobot-pro-320/products/artificial-intelligence-kit-2023-for-mycobot-320" target="_blank" rel="noopener noreferrer nofollow ugc">myCobot 320</a> is a 6-axis collaborative robot designed for user-independent programming and development. With a motion radius of 350mm, it can support a maximum end load of 1000g with a repetitive positioning accuracy of 0.5mm. It provides a fully open software control interface that enables users to quickly control the robotic arm using a variety of mainstream programming languages.The robotic arm uses M5Stack-Basic as the embedded control board, and ATOM as the core control center of the robotic arm.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1615663/image_8jc5GmvQ2U.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
<img src="https://static-cdn.m5stack.com/resource/docs/products/core/basic/basic_01.webp" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>myCobot Adaptive gripper</h3>
<p dir="auto"><img src="https://hackster.imgix.net/uploads/attachments/1615664/image_qE5xSuB2aB.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
The <a href="https://shop.elephantrobotics.com/en-hk/collections/grippers/products/mycobot-pro-adaptive-gripper-black-white" target="_blank" rel="noopener noreferrer nofollow ugc">myCobot adaptive gripper</a> is an end-of-arm actuator used for grasping and transporting objects of various shapes and sizes. It has high flexibility and adaptability and can automatically adjust its gripping force and position based on the shape and size of different objects. It can be combined with machine vision to adjust the gripping force and position of the gripper by obtaining information from vision algorithms. The gripper can handle objects up to 1kg and has a maximum grip distance of 90mm. It is powered by electricity and is very convenient to use. This is the equipment we are using, along with the myCobot 320 AI Kit that we will be using later.</p>
<h2>Vision algorithm</h2>
<p dir="auto">Vision algorithm is a method of analyzing and understanding images and videos using computer image processing techniques. It mainly includes several aspects such as image preprocessing, feature extraction, object detection, and pose estimation.</p>
<p dir="auto"><strong>Image preprocessing:</strong><br />
Image preprocessing is the process of processing the original image to make it more suitable for subsequent analysis and processing. Commonly used algorithms include image denoising algorithms, image enhancement algorithms, and image segmentation algorithms.<br />
<strong>Feature point extraction:</strong><br />
Feature extraction is the process of extracting key features from the image for further analysis and processing. Common algorithms include SIFT algorithm, SURF algorithm, ORB algorithm, HOG algorithm, LBP algorithm, etc.<br />
<strong>Object detection:</strong><br />
Object detection is the process of finding a specific object or target in an image. Commonly used algorithms include Haar feature classifier, HOG feature + SVM classifier, Faster R-CNN, YOLO.<br />
<strong>Pose estimation:</strong><br />
Pose estimation is the process of estimating the pose of an object by identifying its position, angle, and other information. Common algorithms include PnP algorithm, EPnP algorithm, Iterative Closest Point algorithm (ICP), etc.</p>
<h3>Example</h3>
<p dir="auto"><strong>Color recognition algorithm</strong><br />
The verbiage is too abstract. Let us demonstrate this step through practical application. How can we detect the white golf ball in the image below? We shall employ the use of OpenCV's machine vision library.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1615666/_F79c0ZrKy2.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Image processing:</p>
<p dir="auto">Initially, we must preprocess the image to enable the computer to swiftly locate the target object. This step involves converting the image to grayscale.</p>
<p dir="auto"><a href="https://en.wikipedia.org/wiki/Grayscale" target="_blank" rel="noopener noreferrer nofollow ugc">Grayscale image:</a></p>
<p dir="auto">A grayscale image is a method of converting a colored image to a black and white image. It depicts the brightness or gray level of each pixel in the image. In a grayscale image, the value of each pixel represents its brightness, typically ranging from 0 to 255, where 0 represents black and 255 represents white. The intermediate values represent varying degrees of grayness.</p>
<pre><code>import cv2
import numpy as np

image = cv2.imread('ball.jpg')
# turn to gray pic
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

cv2.imshow('gray', gray) 
</code></pre>
<p dir="auto"><img src="https://hackster.imgix.net/uploads/attachments/1615667/image_Oz0GaL3ChI.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Binarization:</p>
<p dir="auto">As we can observe, there is a significant color contrast between the golf ball and the background in the image. We can detect the target object through color detection. Although the golf ball is primarily white, there are some gray shadow areas caused by lighting. Therefore, while setting the pixels of the grayscale image, we must consider the gray areas as well.</p>
<pre><code>lower_white = np.array([180, 180, 180])  # Lower limit
upper_white = np.array([255, 255, 255])  # Upper limit

# find target object
mask = cv2.inRange(image, lower_white, upper_white)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
</code></pre>
<p dir="auto">This step is called binarization, which separates the target object from the background.</p>
<p dir="auto">Contour filtering:</p>
<p dir="auto">After binarization, we need to establish a filter for the contour area size. If we fail to set this filter, we may encounter the result depicted in the image below, where many areas are selected, whereas we only desire the largest one. By filtering out small regions, we can achieve our desired outcome.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1615668/image_stKydqBU8K.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<pre><code>#filter
min_area = 100
filtered_contours = [cnt for cnt in contours if cv2.contourArea(cnt) &gt; min_area]

#draw border
for cnt in filtered_contours:
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 0, 255), 2)
</code></pre>
<p dir="auto"><img src="https://hackster.imgix.net/uploads/attachments/1615669/image_ksvX00frbm.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<pre><code>import cv2
import numpy as np

image = cv2.imread('ball.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

lower_white = np.array([170, 170, 170])   
upper_white = np.array([255, 255, 255])  

mask = cv2.inRange(image, lower_white, upper_white)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
min_area = 500
filtered_contours = [cnt for cnt in contours if cv2.contourArea(cnt) &gt; min_area]

for cnt in filtered_contours:
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(image, (x, y), (x+w, y+h), (0, 0, 255), 2)


cv2.imshow('Object Detection', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
</code></pre>
<p dir="auto">It is important to note that we are utilizing a robotic arm to grasp the object. Hence, merely detecting the target object is insufficient. We must obtain the coordinate information of the object. To achieve this, we use OpenCV's Aruco markers, which are commonly used 2D barcodes for tasks such as camera calibration, pose estimation, and camera tracking in computer vision. Each Aruco marker has a unique identifier. By detecting and recognizing these markers, we can infer the position of the camera and the relationship between the camera and the markers.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1615670/image_ggxC38R8pM.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
<img src="https://hackster.imgix.net/uploads/attachments/1615672/image_Nw4l2a9AFF.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
The two unique Arcuo codes in the picture are used to fix the size of the cropped picture and the position of the arcuo code, and the target object can be obtained through calculation.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1615673/_mdmrUXVG2H.blob?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
With the Aruco marker's positioning, we can detect the location of the target object. We can then convert the x and y coordinates into world coordinates and provide them to the robotic arm's coordinate system. The robotic arm can then proceed with grasping the object.<br />
<img src="/assets/uploads/files/1690940876168-%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230802094700.png" alt="0_1690940889304_微信图片_20230802094700.png" class=" img-fluid img-markdown" /></p>
<pre><code># get points of two aruco
 def get_calculate_params(self, img):
        """
        Get the center coordinates of two ArUco codes in the image
        :param img: Image, in color image format.
        :return: If two ArUco codes are detected, returns the coordinates of the centers of the two codes; otherwise returns None.
        """
        # Convert the image to a gray image 
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        # Detect ArUco marker.
        corners, ids, rejectImaPoint = cv2.aruco.detectMarkers(
            gray, self.aruco_dict, parameters=self.aruco_params
        )

        """
        Two Arucos must be present in the picture and in the same order.
        There are two Arucos in the Corners, and each aruco contains the pixels of its four corners.
        Determine the center of the aruco by the four corners of the aruco.
        """
        if len(corners) &gt; 0:
            if ids is not None:
                if len(corners) &lt;= 1 or ids[0] == 1:
                    return None
                x1 = x2 = y1 = y2 = 0
                point_11, point_21, point_31, point_41 = corners[0][0]
                x1, y1 = int((point_11[0] + point_21[0] + point_31[0] + point_41[0]) / 4.0), int(
                    (point_11[1] + point_21[1] + point_31[1] + point_41[1]) / 4.0)
                point_1, point_2, point_3, point_4 = corners[1][0]
                x2, y2 = int((point_1[0] + point_2[0] + point_3[0] + point_4[0]) / 4.0), int(
                    (point_1[1] + point_2[1] + point_3[1] + point_4[1]) / 4.0)

                return x1, x2, y1, y2
        return None

    # set camera clipping parameters  
    def set_cut_params(self, x1, y1, x2, y2):
        self.x1 = int(x1)
        self.y1 = int(y1)
        self.x2 = int(x2)
        self.y2 = int(y2)

    # set parameters to calculate the coords between cube and mycobot320
    def set_params(self, c_x, c_y, ratio):
        self.c_x = c_x
        self.c_y = c_y
        self.ratio = 320.0 / ratio

    # calculate the coords between cube and mycobot320
    def get_position(self, x, y):
        return ((y - self.c_y) * self.ratio + self.camera_x), ((x - self.c_x) * self.ratio + self.camera_y)
</code></pre>
<h2>Summary</h2>
<p dir="auto">Vision-based control technology for robotic arms is a rapidly developing and widely applied technology. Compared to traditional robotic arm control technology, vision-based control technology boasts advantages such as high efficiency, precision, and flexibility, and can be extensively utilized in industrial production, manufacturing, logistics, and other fields. With the constant evolution of technology such as artificial intelligence and machine learning, vision-based control technology for robotic arms will have even wider application scenarios. In the future, it will be necessary to strengthen technological research and development and innovation, constantly improving the level of technology and application capabilities.</p>
]]></description><link>https://community.m5stack.com/topic/5535/revealing-the-potential-of-mycobotm5stack-ai-kit-vision-algorithms</link><guid isPermaLink="true">https://community.m5stack.com/topic/5535/revealing-the-potential-of-mycobotm5stack-ai-kit-vision-algorithms</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Let AI play Connect4:Implementing using DQN neural network with myCobot 280 M5stack]]></title><description><![CDATA[<h2>Introduction</h2>
<p dir="auto">Today, we shall acquaint ourselves with the subject of artificial intelligence in chess, whereby we shall employ a mechanical arm as an opponent to engage in a game of chess with you. The study of artificial intelligence in chess can be traced back to the 1950s, when computer scientists began to explore the writing of programs that would enable computers to play chess. The most renowned example of this was Deep Blue, developed by IBM, which in 1997 defeated the reigning world chess champion, Gary Kasparov, with a score of 3.5-2.5.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1594447/AgAACgPnCYMgwcEQm2xCYo0ys7Ba7CI6.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Artificial intelligence in chess is akin to granting a computer a mode of deliberation that enables it to achieve victory in a match. There are many such modes, most of which stem from superior algorithms. At its core, Deep Blue's algorithm was based on brute-force search: generating every possible move, conducting searches as deeply as possible, constantly evaluating the game state, and attempting to identify the optimal move.<br />
Now, let me show you how to realize the robot arm to play chess intelligently.</p>
<h2>Connect 4</h2>
<p dir="auto">The game I shall introduce today is known as Connect4, a strategic board game commonly referred to as "Four in a Row". The objective of Connect4 is to achieve a horizontal, vertical, or diagonal sequence of four game pieces within a vertically-oriented grid comprising six rows and seven columns. Two players take turns inserting their respective pieces from the top of the grid, with the pieces falling to the lowest available position within the selected column. Players may select any column in which to place their pieces, provided the pieces are placed only underneath existing pieces.<br />
<img src="/assets/uploads/files/1685428973920-fce141b2-119c-4ef2-8908-d6cd42dc039b-image.png" alt="0_1685428981128_fce141b2-119c-4ef2-8908-d6cd42dc039b-image.png" class=" img-fluid img-markdown" /><br />
As shown in the animation, this is Connect4.</p>
<h2>myCobot 280</h2>
<p dir="auto">The robotic arm selected for the task is the myCobot 280 M5Stack, a powerful desktop six-axis robot arm that employs the M5Stack-Basic as its control core and supports multiple programming languages. The myCobot 280's six-axis structure grants it high flexibility and precision, enabling it to perform a variety of complex operations and movements. It supports multiple programming languages, including Python, C++, and Java, allowing developers to program and control the mechanical arm according to their specific needs. Its user-friendly interface and detailed user manual facilitate rapid familiarization, while its embedded design ensures a compact size, making it easy to carry and store.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1594449/image_M2Haf2TXGl.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
This is the scene we built,we use myCobot280 to play connect4 with us.</p>
<h2>Algorithm for playing chess</h2>
<p dir="auto">Firstly, we must address the crucial matter of which algorithm to employ for playing chess. In other words, we must provide the mechanical arm with a cognitive brain capable of deep contemplation. Allow me to briefly present to you a few commonly used algorithms for playing chess:</p>
<h3>The Minimax Algorithm:</h3>
<p dir="auto">This is a classic game algorithm that is applicable for two-player games. It works by recursively simulating the moves of both the opponent and oneself, evaluating the score of every possible move, and selecting the action with the highest score. The Minimax Algorithm can find the best chess strategy by searching through the tree structure of the game board. This algorithm is a zero-sum game, meaning that one player chooses the option that maximizes their advantage from the available choices, while the other player selects the method that minimizes the advantage of their opponent. The total sum is zero at the beginning. Let me give a simple example of Tic-Tac-Toe to illustrate this.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1594450/AgAACgPnCYMpN7IhtYVN8bn66xZdmRMX.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Max represents us, while Min represents our opponent. At this point, we need to assign a score to every possible outcome, which is known as the Utility. This score is evaluated from our perspective (Max), for example, in the figure above, if I win, the score is +1, if I lose, it is -1, and if it is a tie, it is 0. Therefore, we want to maximize this score, while our opponent wants to minimize it. (In the game, this score is called the static value.) I must mention that Tic-Tac-Toe is a relatively simple game, so it is possible to list all possible outcomes. However, for most games, it is impossible to list all outcomes. According to the computational power of the computer, we may only be able to look forward to 7 or 8 steps, so the score is not as simple as -1, 1, 0. There will be specific algorithms to assign different scores based on the current outcome.</p>
<h3>Alpha-Beta Pruning Algorithm:</h3>
<p dir="auto">This is an optimization of the Minimax Algorithm. It reduces the number of branches to be searched by pruning, thus speeding up the search process. The Alpha-Beta Pruning Algorithm uses upper and lower bounds (Alpha and Beta values) to determine which branches can be discarded, reducing the depth of the search.<br />
Neural Networks and Deep Learning:<br />
The connect4 game algorithm that we designed also uses neural networks and deep learning for gameplay.</p>
<h3>Neural Networks:</h3>
<p dir="auto">Scientists have always hoped to simulate the human brain and create machines that can think. Why can humans think? Scientists have found that the reason lies in the neural network of the human body. Neural networks are mathematical models that simulate the structure and function of the human brain's nervous system. They process information and learn by simulating the connections and signal transmission between neurons. Neural networks are the foundation of all artificial intelligence.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1594451/AgAACgPnCYO8E498675E8LLgUoIahY7y.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
The basic idea of the neural network algorithm is to pass input data to the input layer of the network, then obtain the output layer's results through a series of computations and transmissions in intermediate layers (hidden layers). The training process adjusts the connection weights to minimize the difference between the actual output and expected output, optimizing the performance of the network.<br />
Deep Learning:<br />
Deep learning is a branch of machine learning that focuses on using deep neural networks for learning and reasoning. Deep learning solves complex learning and decision-making problems by constructing deep neural networks, which have multiple intermediate layers (hidden layers). It can be said that deep learning is a learning method that uses neural networks as the core tool. Deep learning not only includes the structure and algorithm of neural networks but also involves training methods, optimization algorithms, and large-scale data processing.</p>
<h2>Project</h2>
<p dir="auto">The project is mainly divided into two parts, hardware and software:<br />
<img src="https://hackster.imgix.net/uploads/attachments/1594452/_Ck6oHA6HMP.jpg?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
The most crucial part of this project is information collection, analysis, and processing. As mentioned earlier, we also used relevant knowledge of neural algorithms and deep learning, and the specific neural network used is the DQN neural network.</p>
<h3>DQN Neural Network:</h3>
<p dir="auto">The DQN neural network was proposed by DeepMind and combines the ideas of deep learning and reinforcement learning. DQN uses a deep neural network to estimate the state-action value function (Q function), enabling optimal decision-making in complex environments. The core idea of DQN is to use a deep neural network as a function approximator to approximate the state-action value function. By taking the current state as input, the neural network outputs the corresponding Q value for each action, that is, predicting the long-term return of that action in the current state. Then, the optimal action is selected and executed based on the Q value.</p>
<h3>Environment Setup:</h3>
<p dir="auto">Firstly, we need to define the Connect4 game using a two-dimensional array to represent the game board and two types of game pieces, red (R) and yellow (Y). We also need to define the end condition of the game, which is when four game pieces of the same color are connected in a line, the game ends.</p>
<pre><code class="language-#Define">self.bgr_data_grid = &lsqb;&lsqb;None for j in range(6)] for i in range(7)]

#Used to display the state of the board
def debug_display_chess_console(self):
    for y in range(6):
        for x in range(7):
            cell = self.stable_grid[x][y]
            if cell == Board.P_RED:
                print(Board.DISPLAY_R, end="")
            elif cell == Board.P_YELLOW:
                print(Board.DISPLAY_Y, end="")
            else:
                print(Board.DISPLAY_EMPTY, end="")
        print()
    print()
</code></pre>
<p dir="auto"><img src="https://hackster.imgix.net/uploads/attachments/1594453/AgAACgPnCYNwa8LwAHFBA7hz1JWPUJ-j.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Here is the code that defines whether the game is over:</p>
<pre><code>def is_game_over(board):
    # Check if there are four consecutive identical pieces in a row.
    for row in board:
        for col in range(len(row) - 3):
            if row[col] != 0 and row[col] == row[col+1] == row[col+2] == row[col+3]:
                return True

    # Check if there are four consecutive identical pieces in a column.
    for col in range(len(board[0])):
        for row in range(len(board) - 3):
            if board[row][col] != 0 and board[row][col] == board[row+1][col] == board[row+2][col] == board[row+3][col]:
                return True

    # Examine if there are four consecutive identical pieces in a diagonal line.
    for row in range(len(board) - 3):
        for col in range(len(board[0]) - 3):
            if board[row][col] != 0 and board[row][col] == board[row+1][col+1] == board[row+2][col+2] == board[row+3][col+3]:
                return True

    for row in range(len(board) - 3):
        for col in range(3, len(board[0])):
            if board[row][col] != 0 and board[row][col] == board[row+1][col-1] == board[row+2][col-2] == board[row+3][col-3]:
                return True

    # Verify if the game board is filled completely.
    for row in board:
        if 0 in row:
            return False

    return True
</code></pre>
<p dir="auto">Building the DQN Neural Network:<br />
We need to define the input layer and output layer of the neural network. The dimension of the input layer should match the state representation of the game board, while the dimension of the output layer should match the number of legal actions. In short, the input layer receives the status information of the game board, and the output layer generates the corresponding action selection.</p>
<h3>Experience Replay Buffer:</h3>
<p dir="auto">Machines need to learn, so we need to build an experience replay buffer to store the agent's experience. This can be a list or queue used to store information such as the state, action, reward, and next state during the game process.<br />
Here is the pseudocode for constructing the experience replay buffer:</p>
<pre><code> class ReplayBuffer:
    def __init__(self, capacity):
        self.capacity = capacity
        self.buffer = []

    def add_experience(self, experience):
        if len(self.buffer) &gt;= self.capacity:
            self.buffer.pop(0)
        self.buffer.append(experience)

    def sample_batch(self, batch_size):
        batch = random.sample(self.buffer, batch_size)
        states, actions, rewards, next_states, dones = zip(*batch)
        return states, actions, rewards, next_states, dones
</code></pre>
<h3>Decision-making:</h3>
<p dir="auto">We have defined a strategy class named EpsilonGreedyStrategy, which uses the ε-greedy strategy for action selection and exploration. In the initialization function <strong>init</strong>(), we specify the exploration rate ε. The select_action() method selects actions based on the Q-value, randomly selects actions with a probability based on the exploration rate or selects the action with the highest Q-value.</p>
<pre><code>class EpsilonGreedyStrategy:
    def __init__(self, epsilon):
        self.epsilon = epsilon

    def select_action(self, q_values):
        if random.random() &lt; self.epsilon:
            action = random.randint(0, len(q_values) - 1)
        else:
            action = max(enumerate(q_values), key=lambda x: x[1])[0]
        return action
</code></pre>
<p dir="auto">Training Framework:<br />
We use the PyTorch framework in Python to construct the training and implement loop training. We regularly evaluate the performance of the agent by playing against the current DQN neural network and pre-trained or other opponents until the preset requirements are met.<br />
<a href="https://twitter.com/i/status/1651528699945291776" target="_blank" rel="noopener noreferrer nofollow ugc">demo</a></p>
<h2>Summary</h2>
<p dir="auto">This article has come to a temporary conclusion. We mainly introduced how the DQN neural algorithm is implemented in Connect4. The next article will introduce how the robotic arm executes the optimal solution. The algorithm described in this article is just the tip of the iceberg. If you are interested in game algorithms, you can refer to relevant books for further understanding.<br />
We are currently in a period of great change, where artificial intelligence is everywhere, not only capable of defeating top players in games but also has a presence in various fields. We must seize the opportunity to keep up with this technology-filled 21st century.<br />
We will soon update the next article. If you are interested, please follow us and leave a message below, which is the best support for us!</p>
]]></description><link>https://community.m5stack.com/topic/5346/let-ai-play-connect4-implementing-using-dqn-neural-network-with-mycobot-280-m5stack</link><guid isPermaLink="true">https://community.m5stack.com/topic/5346/let-ai-play-connect4-implementing-using-dqn-neural-network-with-mycobot-280-m5stack</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Object Tracking on myCobot 280 Jetson Nano: A Case Study]]></title><description><![CDATA[<h2>Introduction</h2>
<p dir="auto">When we saw a video on YouTube of someone using a robotic arm to achieve object tracking, it deeply inspired us. We became very interested in this project and decided to independently develop a similar program.</p>
<p dir="auto"><img src="https://cdn.hackaday.io/images/original/1433151684201201514.gif" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>myCobot 280 M5Stack</h2>
<p dir="auto">The robotic arm used for the operation is the myCobot280 M5Stack. This is a small 6-axis robotic arm produced by Elephant Robotics, with M5Stack-Basic as the microprocessor, ESP32 as the auxiliary control, and a UR collaborative structure. The myCobot280 M5Stack-Basic has a body weight of 800g, a payload of 250g, a working radius of 280mm, and a compact and portable design. Despite its small size, it is powerful and easy to operate, capable of collaborating with humans and working safely.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1568027/image_WbMNU21RuO.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>Process</h2>
<p dir="auto">The following image is a flowchart of the project development process.<br />
<img src="https://cdn.hackaday.io/images/6695771684202822381.jpg" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>Capture the target</h3>
<p dir="auto">Before beginning development, we conducted some research and experiments. We used a camera to capture images of objects and utilized the OpenCV library for recognition. We attempted various methods, but object recognition required machine learning for the target we wanted to identify, which would increase the project development time. Ultimately, we decided to use aruco codes for identification, which allowed us to quickly capture the aruco codes and proceed to the next stage of development.<br />
<img src="https://cdn.hackaday.io/images/4776861684202919859.jpg" alt="alt text" class=" img-fluid img-markdown" /><br />
Code：</p>
<pre><code>def show_video_v2(self):
        # self.robot.init_robot()
        xyz = np.array([0,0,0])
        LIST = []
        num_count = 0
        list_len = 5
        # cmax = [180, 80, 240]
        # cmin = [130, -80, 200]
        cmax = [150, -150, 300]
        cmin = [-150, -250, 200]

        while cv2.waitKey(1) &lt; 0:
            success, img = self.cap.read()
            if not success:
                print("It seems that the image cannot be acquired correctly.")
                break
            # transfrom the img to model of gray
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            # Detect ArUco marker.
            corners, ids, rejectImaPoint = cv2.aruco.detectMarkers(
                gray, self.aruco_dict, parameters=self.aruco_params
            )

            if len(corners) &gt; 0:
                if ids is not None:
                    # get informations of aruco
                    ret = cv2.aruco.estimatePoseSingleMarkers(
                        # '''https://stackoverflow.com/questions/53303730/what-is-the-value-for-markerlength-in-aruco-estimateposesinglemarkers'''
                        corners, 0.025, self.camera_matrix, self.dist_coeffs
                    )
                    # rvec:rotation offset,tvec:translation deviator
                    (rvec, tvec) = (ret[0], ret[1])
                    
                    (rvec - tvec).any()
                    xyz = tvec[0, 0, :] * 1000
                    rpy = rvec[0,0,:]

                    camera = np.array([xyz[0], xyz[1], xyz[2&rsqb;&rsqb;)

                    if num_count &gt; list_len:
                        target = model_track(camera)
                        print("target", target)

                        for i in range(3):
                            if target[i] &gt; cmax[i]:
                                target[i] = cmax[i]
                            if target[i] &lt; cmin[i]:
                                target[i] = cmin[i]

                        pose = np.array([-103, 8.9, -164])
                        coord = np.concatenate((target.copy(), pose), axis=0)

                        # q1 = math.atan(xyz[0] / xyz[2])*180/np.pi
                        mc.send_coords(coord,50,0)
                        
                        
                        # print('target', coord)
                        num_count = 1
                    else:
                        num_count = num_count + 1
                    

                    for i in range(rvec.shape[0]):
                        # draw the aruco on img
                        cv2.aruco.drawDetectedMarkers(img, corners)
            cv2.imshow("show_video", img)
</code></pre>
<h2>Hand-eye calibration</h2>
<p dir="auto">Hand-eye calibration refers to the process of determining the position and orientation of the robot end effector (such as a mechanical arm) relative to the robot base coordinate system in the field of robotics. This process involves pairing the robot end effector with a camera and then determining its position and orientation in the robot base coordinate system by capturing its position and orientation in the camera's field of view.<br />
Hand-eye calibration typically involves a series of movements between the robot end effector and the camera to collect enough data to calculate the transformation matrix between them. This transformation matrix describes the position and orientation of the robot end effector relative to the camera, which can be used to control the robot's motion and accurately perform the required tasks.<br />
In "eye-to-hand" hand-eye calibration, the camera is considered a stationary observer ("eye"), while the robot end effector is considered a moving object in the camera's field of view ("hand"). As the robot end effector moves around the camera, a series of images are collected that contain information about the end effector's position and orientation at different locations and orientations. By analyzing these images, the position and orientation of the robot end effector relative to the camera can be calculated, completing the hand-eye calibration.<br />
The following is the code for processing the coordinate transformation data.</p>
<pre><code>#The function is used to calculate the similarity between cameras.
def calculate_similarity(camera):
    n = camera.shape[0]
    total_similarity = 0
    for i in range(n):
        for j in range(i+1, n):
            vector_a = camera[i]
            vector_b = camera[j]
            dot_product = np.dot(vector_a, vector_b)
            norm_a = np.linalg.norm(vector_a)
            norm_b = np.linalg.norm(vector_b)
            similarity = dot_product / (norm_a * norm_b)
            total_similarity += similarity
    return total_similarity/n
# The function is used to calculate the rate of change in similarity.
def similarity_change_rate(new_similarity):
    global prev_similarity
    if prev_similarity is None:
        prev_similarity = new_similarity
        return 0
    else:
        change_rate = (new_similarity - prev_similarity) / prev_similarity
        prev_similarity = new_similarity
        return change_rate

#The function is used to convert a rotation matrix to Euler angles.
def CvtRotationMatrixToEulerAngle(pdtRotationMatrix):
    pdtEulerAngle = np.zeros(3)

    pdtEulerAngle[2] = np.arctan2(pdtRotationMatrix[1, 0], pdtRotationMatrix[0, 0])

    fCosRoll = np.cos(pdtEulerAngle[2])
    fSinRoll = np.sin(pdtEulerAngle[2])

    pdtEulerAngle[1] = np.arctan2(-pdtRotationMatrix[2, 0], (fCosRoll * pdtRotationMatrix[0, 0]) + (fSinRoll * pdtRotationMatrix[1, 0]))
    pdtEulerAngle[0] = np.arctan2((fSinRoll * pdtRotationMatrix[0, 2]) - (fCosRoll * pdtRotationMatrix[1, 2]), (-fSinRoll * pdtRotationMatrix[0, 1]) + (fCosRoll * pdtRotationMatrix[1, 1]))

    return pdtEulerAngle
# The function is used to convert Euler angles to a rotation matrix.
def CvtEulerAngleToRotationMatrix(ptrEulerAngle):
    ptrSinAngle = np.sin(ptrEulerAngle)
    ptrCosAngle = np.cos(ptrEulerAngle)

    ptrRotationMatrix = np.zeros((3, 3))
    ptrRotationMatrix[0, 0] = ptrCosAngle[2] * ptrCosAngle[1]
    ptrRotationMatrix[0, 1] = ptrCosAngle[2] * ptrSinAngle[1] * ptrSinAngle[0] - ptrSinAngle[2] * ptrCosAngle[0]
    ptrRotationMatrix[0, 2] = ptrCosAngle[2] * ptrSinAngle[1] * ptrCosAngle[0] + ptrSinAngle[2] * ptrSinAngle[0]
    ptrRotationMatrix[1, 0] = ptrSinAngle[2] * ptrCosAngle[1]
    ptrRotationMatrix[1, 1] = ptrSinAngle[2] * ptrSinAngle[1] * ptrSinAngle[0] + ptrCosAngle[2] * ptrCosAngle[0]
    ptrRotationMatrix[1, 2] = ptrSinAngle[2] * ptrSinAngle[1] * ptrCosAngle[0] - ptrCosAngle[2] * ptrSinAngle[0]
    ptrRotationMatrix[2, 0] = -ptrSinAngle[1]
    ptrRotationMatrix[2, 1] = ptrCosAngle[1] * ptrSinAngle[0]
    ptrRotationMatrix[2, 2] = ptrCosAngle[1] * ptrCosAngle[0]

    return ptrRotationMatrix

</code></pre>
<h2>Robotic Arm Control</h2>
<p dir="auto">After this step, object detection and control of the mechanical arm follow, which involves converting the coordinates of the recognized object into motion commands for the mechanical arm. The pymycobot library is used to control the mechanical arm.</p>
<pre><code>#The function is used for visual tracking and calculating the target position.
def Visual_tracking280(coord, camera):
    pose_camera = camera[:3]
    angle_camear = camera[3:]
    r = CvtEulerAngleToRotationMatrix(angle_camear)
    # r = np.array(&lsqb;&lsqb;1, 0, 0],
    #                  [0, 1, 0],
    #                  [0, 0, 1&rsqb;&rsqb;)
    euler = np.radians(coord[3:])
    R = CvtEulerAngleToRotationMatrix(euler)
    offset = np.array([0, 0, -250])
    Roff = np.array(&lsqb;&lsqb;1, 0, 0],
                     [0, -1, 0],
                     [0, 0, -1&rsqb;&rsqb;)
    # Roff = np.array(&lsqb;&lsqb;1, 0, 0],
    #                  [0, 1, 0],
    #                  [0, 0, 1&rsqb;&rsqb;)
    vector = pose_camera + offset
    # print("R", R)
    # print("r", r)

    move_pos = np.dot(np.dot(R, r), Roff).dot(vector)
    pos = coord[:3] + move_pos
    # angle = np.array(CvtRotationMatrixToEulerAngle(np.dot(np.dot(R, r), Roff))) * 180/np.pi
    angle =  coord[3:]
    target = np.concatenate((pos, angle))
    return target
    
    #Calculate the target position based on the camera coordinates.
def model_track(camera):
    model_pos = np.array([-camera[0], -camera[2], -camera[1&rsqb;&rsqb;)
    camera_pos = np.array([-37.5, 416.6, 322.9])
    target_pos = model_pos + camera_pos
    # print("model_pos", model_pos)
    # print("target_pos", target_pos)
    return target_pos

</code></pre>
<p dir="auto">Finally, let's summarize the logical relationship of the project.<br />
<img src="https://cdn.hackaday.io/images/4871371684203022760.jpg" alt="alt text" class=" img-fluid img-markdown" /><br />
Let's take a look at how it performs.<br />
<img src="https://cdn.hackaday.io/images/original/6687121684203051230.gif" alt="alt text" class=" img-fluid img-markdown" /><br />
It may be noticed that sometimes myCobot does not move. This is because its body was blocking the camera, preventing it from capturing the target object. When moving objects, it is important to ensure that the mechanical arm body does not block the camera.</p>
<p dir="auto">This code is applicable to the entire myCobot280 series, including Pi, Jetson Nano, and other versions. The parameters may need to be adjusted based on the specific version being used.</p>
<p dir="auto">People often compare the Jetson Nano with the Raspberry Pi. I have tried this program on two different robotic arms, and it is evident that the Jetson Nano version is much more responsive than the Raspberry Pi, owing to its superior computational power.There is a noticeable delay of approximately one second between them as observed by the naked eye.</p>
<h2>Summary</h2>
<p dir="auto">During the debugging process, we found that the tracking effect was not very smooth and responsive. We adjusted the smoothness by controlling the detection cycle, but it was necessary to slowly move the tracked object to achieve better results. There are still some shortcomings, as the body of the mechanical arm may block the camera's field of view when the camera is fixed, making it impossible to proceed with the next tracking step. One solution we thought of is to move the camera to a position where it is not blocked (which would require recalculating the coordinates). If you have any better ideas, please feel free to communicate with us! Thank you for your patience.</p>
]]></description><link>https://community.m5stack.com/topic/5302/object-tracking-on-mycobot-280-jetson-nano-a-case-study</link><guid isPermaLink="true">https://community.m5stack.com/topic/5302/object-tracking-on-mycobot-280-jetson-nano-a-case-study</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Deep Machine Vision and Random Grasping with Robotic Arms]]></title><description><![CDATA[<h2>Introduction</h2>
<p dir="auto">Today, I would like to share with you my experience using the myCobot320 M5 and FS820-E1 depth camera for an unordered object grabbing demonstration. Why did I choose to use a depth camera and robotic arm for this case study?</p>
<p dir="auto">The commonly used 2D camera can capture two-dimensional images with pixel values in the horizontal and vertical directions. These cameras are typically used to capture static scenes or moving objects, and cannot provide depth information. In machine vision applications, 2D cameras can be used for tasks such as image classification, object detection, and recognition.</p>
<p dir="auto">In contrast, depth cameras can capture depth information, allowing for the acquisition of three-dimensional information about objects. These cameras use various techniques to measure object depth, such as structured light, time-of-flight, and stereo vision. In machine vision applications, 3D cameras can be used for tasks such as point cloud segmentation, object recognition, and 3D reconstruction.</p>
<p dir="auto">The information captured by 2D cameras is inadequate for certain special cases, hence the use of depth cameras to obtain more information, such as the length, width, and height of objects.</p>
<p dir="auto">Let us begin our topic for today.</p>
<h2>FS820-E1</h2>
<h3>Environment building</h3>
<p dir="auto">Firstly, I need to set up the development environment for the FS820-E1 depth camera using RVS, which is the software used for developing this depth camera. By utilizing the visual operator in RVS, I can quickly construct the node for the grabbing function.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585620/AgAACgPnCYMlFUFWrltBlKRgPiKWk82X.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
In the resource window located at the top left corner, locate the TyCameraResource operator and add it to the ResourceGroup in the operator graph. In the operator list, search for the TyCameraAccess and trigger operators, and add them to the operator graph. Adjust the operator parameters according to the requirements. Then, click on Run and set the Trigger-&gt;true in the property panel to visualize the data.</p>
<p dir="auto">TyCameraResource operator</p>
<p dir="auto">● The start and stop operators are used to respectively initiate and terminate the thread of the resource operator. The auto_start option is also used to initiate the resource operator. If it is checked, the resource thread will only automatically start when entering the running state for the first time after opening the RVS software.</p>
<p dir="auto">● The reset option is used to reset the attribute parameters if they need to be changed after opening the resource thread.</p>
<p dir="auto">TyCameraAccess operator</p>
<p dir="auto">● Open the visualization properties for cloud, RGB, and depth, and set the cloud_color to -2, which represents the true color.<img src="https://hackster.imgix.net/uploads/attachments/1585621/AgAACgPnCYPweAllk61Dbag3YpFzPC5o.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>myCobot 320-M5Stack</h2>
<p dir="auto">The myCobot 320 is a practical robot designed for user-independent programming and development. The product has a maximum effective arm span of 350mm, a maximum load of 1KG, and a repetitive positioning accuracy of ±0.5mm. It supports development in various programming languages.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585622/AgAACgPnCYNxKpXzFahKR4TfVQd-JC3G.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>Environment building</h3>
<p dir="auto">For this project, Python is being used and a compiling environment for Python needs to be set up, as well as installing the Pymycobot library, which enables control of the robotic arm's movement.<br />
<code> pip install pymycobot --upgrade</code><img src="https://hackster.imgix.net/uploads/attachments/1585623/AgAACgPnCYMrJSL-AjRCIJATQ9hb-kOe.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
PS: It is recommended to use a computer graphics card that is at least a 1060 2G discrete graphics card for this project because it requires image recognition and other operations that can benefit from a higher-performing graphics card. The better the graphics card's performance, the faster the program will run. A 3060 graphics card is recommended.</p>
<h2>Random object grasping.</h2>
<p dir="auto">Next, we will implement the random object grasping of the robotic arm, which can accurately grasp the object in any posture. The following image shows the overall operator graph, which is the unstacking.xml.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585624/AgAACgPnCYO3Wtp0rDFKQ4l6pcvP4g7j.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>Hand-eye calibration</h3>
<p dir="auto">Using a chessboard pattern for hand-eye calibration.</p>
<p dir="auto">Preparation:</p>
<p dir="auto">● Prepare a chessboard, determine the number of rows and columns, and the length of each square (in mm).</p>
<p dir="auto">● Hand-eye calibration can be divided into two types: eye in hand and eye to hand. Depending on the situation, fix the calibration board and the camera. Here we choose eye to hand calibration.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585625/AgAACgPnCYOaF_6ceHpGF783Ys-JLcvQ.jpeg?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>Data recording</h3>
<p dir="auto">open unstacking_runtime/HandEyeCalibration/HandEyeCalibration.xml<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585628/image_X8hbEK2fH9.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Correctly fill in the number of rows and columns of the calibration board, the unit length of the calibration board cells, and the file path for saving the calibration data in the property panel.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585629/image_RrmcQUEu3H.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Before starting the calibration process, make sure that the camera can fully recognize the complete chessboard, and during the calibration process, the chessboard must be fixed and cannot be moved. After running the process, you will get 18 sets of data.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585630/image_xAtqgvGGWp.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
<img src="https://hackster.imgix.net/uploads/attachments/1585632/AgAACgPnCYNuPhxlIkpNaaLzkBpAiJV7.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>Calculation of indicator results</h3>
<p dir="auto">If the positional error is within 0.005 (5mm), then it is considered an ideal result.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585631/image_0E4tn1t3KF.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
<h3>Coordinate system conversion</h3>
<p dir="auto">The following steps aim to transform the coordinate system of the point cloud from the camera RGB lens coordinate system to the robot coordinate system, which involves camera extrinsic parameters and hand-eye calibration results.</p>
<p dir="auto">Steps:</p>
<ol>
<li>
<p dir="auto">Right-click in the operator graph and select "Import Group XML here" to import the HandToEye_Depth2Robot.group.xml from the RVSCommonGroup. Besides this file, there is also HandInEye_Depth2Robot.group.xml.</p>
</li>
<li>
<p dir="auto">Connect the pose port of the hand-eye calibration data group to the rgb2robot port of the HandToEye_Depth2Robot group.</p>
</li>
<li>
<p dir="auto">Drag in the LoadCalibFile operator to load the calibration file, connect the finished port to the start port of the HandToEye_Depth2Robot group, connect the extrinsic_pose port to the rgb2depth port, and connect the start port to the InitTrigger port of the finished port. The specific connections are as follows:<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585633/image_QUZuoQIjQp.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
</li>
<li>
<p dir="auto">Click on the Group, find the rgb2tcp operator, and in the properties panel, paste the hand-eye calibration results in the "pose" property.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585634/image_39T6asi5Hr.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
</li>
<li>
<p dir="auto">Through the previous steps, we have obtained the transformation matrices from the RGB camera to the robot coordinate system (rgb2robot) and from the depth camera to the robot coordinate system (depth2robot). Here, we will transform the point cloud from the depth camera coordinate system to the robot coordinate system.</p>
</li>
<li>
<p dir="auto">First, drag the Transform operator into the graph and select "PointCloud" as the type. Connect the depth2robot port to the pose input port of this operator, and connect the pointcloud port of the LoadLocalData operator group to the same-named input port of this operator.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585635/image_Jwg76GbuBc.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
</li>
</ol>
<h2>AI training</h2>
<h3>Acquire training images</h3>
<p dir="auto">To open the file unstacking_runtime/MaskRCNN/ty_ai_savedata.xml, you can use a text editor like Notepad or a code editor like Visual Studio Code. The contents of the file are similar to recording RGB images, and you just need to adjust the string parameter in EmitString to the desired file path. Once you have set the file path, you can click on Capture to record the images. It is recommended to record as many images as possible to ensure stability in the data.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585636/image_IdQwtPlLOG.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Annotate the trained model<br />
Currently, we have recorded the RGB annotations. We recommend using the labelme software for annotation, and this document provides a method for installing labelme.</p>
<p dir="auto">● 1. Install pip according to the official website:</p>
<p dir="auto"><a href="https://pip.pypa.io/en/stable/installation/" target="_blank" rel="noopener noreferrer nofollow ugc">https://pip.pypa.io/en/stable/installation/</a></p>
<p dir="auto">● 2. Install PyQt5:</p>
<p dir="auto"><code>pip install PyQt5</code><br />
● 3. Install labelme:</p>
<p dir="auto"><code>pip install labelme</code><br />
Preparation:</p>
<p dir="auto">First, determine the task goal and clarify which objects need to be detected during the detection process and which objects do not need to be detected, so as to carry out targeted annotation.</p>
<p dir="auto">The annotation conditions given do not need to be overly strict. Do not think according to human thinking, but whether the annotation ideas set by yourself are easy to implement in the code.</p>
<p dir="auto">Process:</p>
<p dir="auto">● Open labelme in the terminal and click "OpenDir" to select the path where our annotations are located (the Emit operator string path in step 3.2.1 for collecting training images).</p>
<p dir="auto">● Click "Create Polygons" to draw a red border around the wooden blocks.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585637/image_k12K4PQPdm.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
After finishing, a naming dialog will pop up. Please name it "wooden block" for the first time, and select it directly for subsequent boxes of the same type.</p>
<p dir="auto">● When all the boxes in the image have been labeled, click "Save" to save them with the default folder and name. Then select "Next Image" to switch to the next image.</p>
<p dir="auto">Train AI model<br />
Open the file unstacking_runtime/MaskRCNN/ty_ai_train.xml, and adjust the paths for data_directory and classnames_filepath. Then click on the "start_train" button to start the training process.</p>
<p dir="auto">After the training process is completed, a folder named "train_output" will be generated. In this folder, there will be a model file (ending in.pth) which contains the required weights for the trained model.</p>
<p dir="auto">AI reasoning</p>
<ol>
<li>
<p dir="auto">Drag in an Emit operator, select "pose" for the type attribute, rename it to "Grasp Reference Pose", and input "3.141592654" for the pose_roll. This operator will be used in subsequent operators. Connect the pose port of this operator to the down_pose port of the Compute Grasping Point group.</p>
</li>
<li>
<p dir="auto">Double-click to expand the Compute Grasping Point group. The data needs to be pre-trained using the MaskRCNN network. Change the type of the AIDetectGPU operator to MaskRCNN and modify the rest of the configuration file parameters accordingly. Since the AI inference operator needs to be initialized before running, an extra Trigger (type is InitTrigger) needs to be added before the operator.</p>
</li>
<li>
<p dir="auto">The AI inference operator will obtain the position region of the target in the 2D image (i.e., the mask image, corresponding to the obj_list port). Next, we need to convert these position regions to 3D point clouds, which is the ProjectMask operator in the Compute Grasping Point group. For the ProjectMask operator, we not only need to input the obj_list obtained by the AI inference operator, but also the 2D image corresponding point cloud, the transformation matrix between the 2D image camera coordinate system and the point cloud coordinate system, and the intrinsic parameters of the camera's RGB lens. Here, the point cloud has been converted to the robot coordinate system, so the transformation matrix from the RGB lens to the robot coordinate system needs to be input. The intrinsic parameters of the camera's RGB lens can be directly read from the camera parameter file. After the operator runs, a list of point clouds for all detected targets will be obtained.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585638/image_OgkWlkycrz.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Robotic arm positioning and grasping<br />
location and Identification<br />
According to the AI inference process, the point cloud list of all detected targets in the robot coordinate system has been obtained. Next, we need to obtain the centroid coordinates of its point cloud.</p>
</li>
<li>
<p dir="auto">Double-click to expand the Find Target group in the Calculate Grasp Point group. We need to first select the wooden block, and then sort the wooden blocks based on their Z-axis coordinates, selecting the topmost wooden block. Therefore, the FilterBoxList operator is used here and renamed to "PointCloud Height Sorting", with the following property values adjusted:</p>
</li>
<li>
<p dir="auto">Obtain the plane using the FindElement operator, select "Plane" for the type, and obtain a plane suitable for grasping in the point cloud. Adjust the distance_threshold property value of the operator to adjust the selected plane. Open the cloud visualization property to view the selected plane.</p>
</li>
<li>
<p dir="auto">Obtain the center point of the plane using the MinimumBoundingBox operator, rename it to "Get Bounding Box", select "ApproxMVBB" for the type attribute to obtain a convenient coordinate center point for the robot to grasp. Here, give the operator a ref_pose, which is connected to "TowardsDownPose" mentioned in 3.3.4 during AI inference, indicating a 180° rotation around the X-axis, so that the Z-axis faces downward for ease of robot grasping. Open the box and box_pose visualization properties in the "GetBoxCube" attribute panel to display the calculated center point of the plane.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585639/image_1oC8wkHptw.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
</li>
<li>
<p dir="auto">Adjust the direction of the wooden block using the AdjustBoxNode operator, which selects objects with a length greater than their width and changes the object pose. Here, select a yaw of 90°.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585640/image_ofu6Udhc0c.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Grasp by the robotic arm<br />
After completing the above operations, the target point coordinates have been obtained, and it is necessary to establish a TCP connection between the robot and the RVS software and carry out actual grasping.</p>
</li>
<li>
<p dir="auto">Write TCP communication code (RobotControl_Elephant.py). The following is a snippet of the code that implements TCP communication between RVS software and the robotic arm.</p>
</li>
</ol>
<pre><code>#CAPTURE
print("***get pose***%s"%time.asctime())
capture_cmd = "GET_POSES \n"
capture_bytes=bytes(capture_cmd,encoding="utf-8")
sock_rvs.send(capture_bytes)
#recv CAPTURE
data = sock_rvs.recv(socket_buf_len)
print("---------------------------get data----------------------------")
print(data)
print("***data end***%s"%data[-1:])

print("***capture_receive***%s"%time.asctime())
if int(data[-1:]) == 1:
    print("***received CAPTURE result***\n")
if int(data[-1:]) == 2:
    print("***All finished!***")
    #P_FLAG = bool(1-P_FLAG)
    #print("change poision")
    continue
    #break
</code></pre>
<ol start="2">
<li>
<p dir="auto">Adjust the target point coordinates using the ScalePose operator. Set the type to "Normal" and adjust the scale_rpy property to convert the roll, pitch, and yaw values from radians to degrees.</p>
</li>
<li>
<p dir="auto">Finally, connect the finished and pose_list ports of the ScalePose operator to the MirrorOutput port of the outermost operator group and connect it back to the HandEyeTCPServer operator. With this, the project file editing is complete.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1585642/image_vVPb92wlSz.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /></p>
</li>
</ol>
<h2>Show results</h2>
<p dir="auto">After completing the above steps, under the unstacking.xml project, click Run, and run the RobotControl_Elephant.py file at the same time. After identifying multiple blocks, select one of the block poses and send it to the robotic arm for gripping.<br />
<img src="https://cdn.hackaday.io/images/original/7748771682671325815.gif" alt="alt text" class=" img-fluid img-markdown" /></p>
<h2>Summary</h2>
<p dir="auto">Overall, this is just a small part of what a depth camera can do. In the future, we may even consider stacking these objects together or using other irregular shapes to demonstrate its powerful performance. By training the model in advance, we can achieve the desired results. What do you expect me to do with it? Please leave a message below. Your likes and follows will be my motivation for updating more content!</p>
]]></description><link>https://community.m5stack.com/topic/5252/deep-machine-vision-and-random-grasping-with-robotic-arms</link><guid isPermaLink="true">https://community.m5stack.com/topic/5252/deep-machine-vision-and-random-grasping-with-robotic-arms</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Reinforcement Learning for Gripping Task of myCobot using Isaac Gym]]></title><description><![CDATA[<p dir="auto">This article is republished from Tatsushi Matsubayashi [1] of ALBERT Inc.[2]<br />
Link:<a href="https://blog.albert2005.co.jp/2023/03/28/isaac-gym-mycobot/" target="_blank" rel="noopener noreferrer nofollow ugc">https://blog.albert2005.co.jp/2023/03/28/isaac-gym-mycobot/</a><br />
<img src="https://cdn.hackaday.io/images/original/1860261680848310396.gif" alt="alt text" class=" img-fluid img-markdown" /><br />
Greetings, I am from the Advanced Technology Department. Following our previous blog post titled "Controlling myCobot using RealSense D455 for Spatial Recognition", I will now introduce an experiment utilizing myCobot. This time, the experiment will be conducted using a simulator rather than a physical machine. When attempting deep reinforcement learning with robots, it can be challenging to prepare large amounts of training data on a physical machine. However, with a simulator, it is easy to collect massive datasets. Nevertheless, simulators may appear daunting to those who are unfamiliar with them. Therefore, we tried using Isaac Gym, developed by Nvidia, which allowed us to achieve everything from creating an experimental environment to conducting reinforcement learning with almost nothing but Python code. In this post, I will introduce the method we used.</p>
<ol>
<li>Introduction<br />
1.1 What is Isaac Gym?<br />
Isaac Gym is a physics simulation environment developed by Nvidia for reinforcement learning. Based on the OpenAI Gym library, the physics calculations are performed on the GPU and the results can be received as Pytorch GPU tensors, enabling fast simulation and learning. Physics simulation is carried out using PhysX, and it also supports soft body simulation using FleX (although some features are limited when using FleX).</li>
</ol>
<p dir="auto">The latest version as of January 2023 is Preview4. While earlier versions had noticeable bugs, versions 3 and onwards have seen improvements and added functionality, making it a very attractive simulation environment. A future release of Omniverse Isaac Gym, integrated with Isaac Sim, is planned. However, Isaac Gym itself is standalone and can be used for experiments in Python. In a previous blog post ("GPU Server Expansion and A6000 Benchmarking"), it was mentioned that research and development using Omniverse Isaac Simulator had begun, but Isaac Gym was prioritized for reinforcement learning simulation. The biggest benefit of integrating Isaac Gym with Omniverse would likely be the ability to use photorealistic visuals for image recognition and high-precision continuous body simulation, such as with ray tracing. It will be exciting to see how this develops in the future.</p>
<p dir="auto">PhysX is a physics engine developed by Nvidia, enabling real-time physics calculations on the simulator's GPU. Although the version used by Isaac Gym has not been specified in publicly available arXiv or documentation, it is likely based on PhysX 4, given its release timing and separation from FleX. In Omniverse, PhysX 5 is used and FleX is integrated as well.</p>
<p dir="auto">FleX is also a physics engine developed by Nvidia, but it enables the representation of soft bodies and fluids using particle-based simulation, in contrast to PhysX's rigid body simulation.</p>
<p dir="auto">1.2 Purpose of this article<br />
I will tell you how I was able to easily create and learn reinforcement learning tasks using Isaac Gym. As an actual test case, I will introduce an object grasping task created by importing myCobot introduced in the previous article into the simulation environment.</p>
<p dir="auto"><a href="https://blog.albert2005.co.jp/2022/12/21/realsense-d455_mycobot/" target="_blank" rel="noopener noreferrer nofollow ugc">https://blog.albert2005.co.jp/2022/12/21/realsense-d455_mycobot/</a></p>
<p dir="auto">1.3 Environment<br />
PC1: Ubuntu 20.04, Python 3.8.10, Nvidia RTX A6000</p>
<p dir="auto">PC2: Ubuntu 18.04, Python 3.8.0, Nvidia RTX 3060Ti</p>
<p dir="auto">Please note that Nvidia Driver 470 or later is required.</p>
<p dir="auto">2.Install<br />
In this chapter, we will install Isaac Gym and IsaacGymEnvs. The recommended environment is Ubuntu 18.04, 20.04, Python 3.6~3.8, and Nvidia Driver==470. Please note that since python_requires&lt;3.9 is described in Isaac Gym's <a href="http://setup.py" target="_blank" rel="noopener noreferrer nofollow ugc">setup.py</a>, it cannot be used as is for versions 3.9 and above. Testing has not been performed on Ubuntu 22.04, but it is probably okay.</p>
<p dir="auto">2.1 Isaac Gym<br />
You can download the Isaac Gym main package for free from Nvidia's developer page. The documentation is saved in HTML format in the "docs" directory of the package (please note that it is not available on the website). After downloading, you can install it with the following command:</p>
<p dir="auto">$ cd isaacgym/python$ pip install -e .<br />
However, since PyTorch is specified as "torch ==1.8.0" and "torchvision ==0.9.0", you should install it first from the official page that matches your environment when using your GPU. Docker and Conda virtual environment setup files are also available. Since I use venv to manage my Python virtual environment, I will proceed with pip. Please note that I have written "＞" in full-width characters due to a code block issue</p>
<p dir="auto">2.2 IsaacGymEnvs<br />
IsaacGymEnvs is a Python package for benchmark testing reinforcement learning environments in Isaac Gym. By referring to the implemented tasks, one can easily construct reinforcement learning environments using the reinforcement learning algorithms implemented in rl-games. Even for those who plan to write their own reinforcement learning algorithms, it is recommended to try learning with Isaac Gym using this package. Originally included in Isaac Gym, it was separated in Preview3 and is now publicly available on GitHub.</p>
<p dir="auto">$ git clone <a href="https://github.com/NVIDIA-Omniverse/IsaacGymEnvs.git" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/NVIDIA-Omniverse/IsaacGymEnvs.git</a><br />
$ cd IsaacGymEnvs$ pip install –e .<br />
With this, the necessary installation is now complete.</p>
<ol start="3">
<li>Demo<br />
When you install Isaac Gym and take a look inside the package, you'll see that there are many sample environments available. These are also featured in the documentation, but in this article, we'll highlight some of the samples that are relevant to creating custom reinforcement learning environments in Chapter 4. If you've set up your environment, it's a good idea to try running some of these samples and see what they can do. You might even find that they provide some guidance on how to use the API to accomplish things you're interested in trying out (and if you're still not sure, don't hesitate to read through the documentation).</li>
</ol>
<p dir="auto">3.1. Isaac Gym<br />
As of Preview4, there are 27 sample environments available.</p>
<p dir="auto">● "1080_balls_of_solitude.py"</p>
<p dir="auto">The "1080_balls_of_solitude.py" script generates a pyramid-shaped group of balls that fall down. Running the script without options only allows collisions between balls within the same environment (i.e. within the same pyramid). The "--all_collisions" option enables collisions with balls from other environments, while the "--no_collisions" option disables collisions between objects within the same environment. This script also demonstrates how to configure the arguments of the "create_actor" function to add objects to the environment.</p>
<p dir="auto">● "dof_controls.py"</p>
<p dir="auto">This script features an actor that moves in 3D, which is a variation of the well-known Cartpole problem in OpenAI Gym. It demonstrates how to set the control methods for each degree of freedom (DOF) of the robot, which can be either position, velocity, or force. Once set, these control methods cannot be changed during simulation, and the actor can only be controlled through the selected methods. Forgetting to set these control methods can cause the actor to fail to move.</p>
<p dir="auto">● ”franka_nut_bolt_ik_osc.py“</p>
<p dir="auto">This script showcases Franka Robotics' multi-jointed robot arm Panda picking up a nut and screwing it onto a bolt. The arm is controlled using inverse kinematics (IK). The file name includes "OSC, " but OSC control is not implemented in this script. However, the script "franka_cube_ik_osc.py" includes OSC control.</p>
<p dir="auto">With the addition of SDF collision in Preview4, high-resolution collision file loading is possible, allowing for precise collision calculations between the nut and bolt grooves (Figure 1). While the initial SDF loading can take some time, subsequent loads are cached and will start quickly.<br />
<img src="https://cdn.hackaday.io/images/original/2400751680849320342.gif" alt="alt text" class=" img-fluid img-markdown" /><br />
Figure 1: Simulation of a panda arm driving a nut onto a bolt</p>
<p dir="auto">● interop_torch.py</p>
<p dir="auto">This script shows how to use the function get_camera_image_gpu_tensor to directly obtain sensor data from the camera on the GPU. The obtained data can be output as an image file using OpenCV, just like a regular physical camera. When executed, the script creates a directory called interop_images and saves the camera images there. Since simulation data is not exchanged between the GPU and CPU, fast image processing is possible. However, if using a multi-GPU environment, an error may occur. One solution suggested on the forum is to limit the GPU usage with CUDA_VISIBLE_DEVICES=0, but this did not work in the environment used for this script.</p>
<p dir="auto">3.2. IsaacGymEnvs<br />
There are 14 reinforcement learning tasks implemented, and benchmark tests can be performed using the scripts in the tasks directory.</p>
<p dir="auto">● About the configuration file</p>
<p dir="auto">A configuration file written in YAML is prepared for each task. Common settings are in the config.yaml in the cfg directory, and settings can be changed without changing the YAML file with command line options using Hydra. The detailed settings for each task environment and PhysX are stored in the cfg/task/ directory, and the algorithm selection and structure are stored in the cfg/train/ directory.</p>
<p dir="auto">● About algorithm implementation</p>
<p dir="auto">The reinforcement learning algorithm uses the PPO implementation in Rl-games. Although the docs/rl_examples.md mentions the option to select SAC, it is not currently included in the repository.</p>
<p dir="auto">NN layers are typically MLPs, and some models also include LSTM layers as RNN layers. Although CNN layers can also be added, there are no sample models with CNN layers included. In section 5.2, we will discuss our experience adding CNN layers to a model.</p>
<p dir="auto">The sample code can be executed in the isaacgymenvs directory where <a href="http://train.py" target="_blank" rel="noopener noreferrer nofollow ugc">train.py</a> is located.</p>
<p dir="auto">● Cartpole<br />
python <a href="http://train.py" target="_blank" rel="noopener noreferrer nofollow ugc">train.py</a> task=Cartpole [options]<br />
This is the classic cartpole task where the goal is to move the cart in a way that the pole does not fall. By default, the model is trained for 100 epochs, which takes about 2 minutes on a PC2 RTX 3060Ti environment, and only 15 seconds in headless mode (without the viewer). When testing the model with inference, it performs well and the pole remains upright (after 30 epochs of training, the model is sufficiently trained to keep the pole upright). Although it may seem simple, the fact that the model can learn to complete this task successfully is reassuring.</p>
<p dir="auto">● Franka Cube Stack<br />
python <a href="http://train.py" target="_blank" rel="noopener noreferrer nofollow ugc">train.py</a> task=FrankaCubeStack [options]<br />
This is a task where a Panda arm is used to stack boxes. The joint movements of the 7-axis arm are learned step by step. The default setting is 10, 000 epochs, but the arm movements can be learned in about 1, 000 epochs. On a PC1 RTX A6000 environment, 1, 000 epochs of training took about 20-30 minutes to complete. Figures 2 and 3 show the before and after states of the arm, where it goes from randomly moving to successfully grabbing and stacking boxes.</p>
<p dir="auto">The action space consists of 7 dimensions for the arm joints, while the observation space is a total of 26 dimensions. The reward function is designed to scale differently for actions that involve getting closer to the box, lifting the box, moving the boxes closer to each other, and successfully completing the stacking task.</p>
<p dir="auto">It's surprising how easily the arm can learn this level of task. However, it's important to note that the learning assumes a defined world coordinate system and the known positions and orientations of the objects. Therefore, applying this learned behavior to a physical robot may not be as straightforward.</p>
<p dir="auto">Breakdown of 26-dimensional observation:</p>
<p dir="auto">● 7 dimensions for the position and orientation of the box being moved</p>
<p dir="auto">● 3 dimensions for the vector from the box being stacked to the box being moved</p>
<p dir="auto">● 7 dimensions for the gripper's grasp position and orientation</p>
<p dir="auto">● 9 dimensions for the arm joints and gripper fingers<br />
<img src="https://cdn.hackaday.io/images/original/2387001680851314018.gif" alt="alt text" class=" img-fluid img-markdown" /><br />
Figure 2: FrankaCubeStack before training<br />
<img src="https://cdn.hackaday.io/images/original/7255071680854233433.gif" alt="alt text" class=" img-fluid img-markdown" /><br />
Figure 3: FrankaCubeStack after training</p>
<p dir="auto">Some common options in <a href="http://train.py" target="_blank" rel="noopener noreferrer nofollow ugc">train.py</a> are:</p>
<p dir="auto">● headless (default: False): When set to True, the viewer is not launched. This is useful for heavy training or when capturing camera images, as the viewer can slow down the process significantly.</p>
<p dir="auto">● test (default: False): When set to True, the learning mode is turned off, allowing you to run the environment without training. This is useful for environment generation and checking the learning results.</p>
<p dir="auto">● checkpoint (default: ''): Specifies the PyTorch weight file to load. The learning results are saved in runs/&lt;task name&gt;/nn/&lt;task name&gt;.pth, and this option is used for resuming training or testing.</p>
<p dir="auto">● num_envs (default: int): Specifies the number of parallel learning environments. It's important to set an appropriate number to avoid heavy viewers during testing (this option can also be set during training, but changing it can cause errors due to batch size and interference).</p>
<p dir="auto">Note that <a href="http://train.py" target="_blank" rel="noopener noreferrer nofollow ugc">train.py</a> configures horizon_length and minibatch_size, but batch_size = horizon_length * num_actors * num_agents, and batch_size must be divisible by minibatch_size. Additionally, num_actors and num_agents are proportional to num_envs, so changing only num_envs can cause errors.</p>
<p dir="auto">Other samples can be tried easily with just the environment, so give them a try for some interesting tests.</p>
<p dir="auto">3.3 Viewer Tips<br />
● Drawing a collision mesh</p>
<p dir="auto">The simulator usually renders an object's visual mesh, but in Isaac Gym's Viewer, you can change it to render the collision mesh instead. To do this, go to the Viewer tab in the menu window and check "Render collision meshes". If an object is behaving strangely, it's a good idea to check if the collision mesh is loaded correctly (sometimes the visual and collision meshes have different orientations, or the mesh may not have loaded correctly or with enough detail in the simulator).<br />
<img src="https://hackster.imgix.net/uploads/attachments/1579029/AgAACgPnCYMqZjp57JZBS4MHtOsawYYm.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Figure 4: Drawing the collision mesh</p>
<p dir="auto">● Reduce drawing environment</p>
<p dir="auto">You can reduce the rendering environment to only one without changing any settings. By checking "Show only selected env" in the Actors menu, as shown in Figure 5, only the selected environment will be displayed. If there are any strange behaviors, you can debug by outputting the environment number and only rendering that environment. This also lightens the rendering load and can increase FPS.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1579030/AgAACgPnCYNlxDAWe11E1qT6EyGXq0Br.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Figure 5: Numbering the drawing environment</p>
<p dir="auto">● Change initial camera position</p>
<p dir="auto">The initial camera position and orientation can be set using gymapi's viewer_camera_look_at(viewer, middle_env, cam_pos, cam_target). In task scripts for training, you need to override the set_viewer function to make changes.</p>
<ol start="4">
<li>Original environment and task creation<br />
It's finally time to create the original task for the main subject.</li>
</ol>
<p dir="auto">4.1. Preparation<br />
Prepare the script and configuration files. The goal is to learn a simple task of lifting a box, using Mycobot for object picking. Therefore, we will proceed with creating a task named "MycobotPicking". We need three files:</p>
<p dir="auto">● tasks: the main Python script</p>
<p dir="auto">● cfg/task: YAML configuration file for environment and simulation parameters</p>
<p dir="auto">● cfg/train: YAML configuration file for learning algorithms, neural network layers, and parameters.</p>
<p dir="auto">We can refer to the "FrankaCubeStack" task mentioned earlier and create these files accordingly. The configuration files are especially important and we can copy and modify them according to our requirements.</p>
<p dir="auto">As shown in the demo, we can load the task script from the <a href="http://train.py" target="_blank" rel="noopener noreferrer nofollow ugc">train.py</a> file using command-line options. Therefore, we need to add an import statement for the task class in the <a href="http://init.py" target="_blank" rel="noopener noreferrer nofollow ugc">init.py</a> file in the tasks directory, along with the task name when passing arguments.</p>
<p dir="auto">4.2. Environment Creation<br />
The task class is created by inheriting from the VecTask class in the tasks/base directory, and the task has the following structure as shown in Figure 6.<br />
<img src="https://hackster.imgix.net/uploads/attachments/1579033/7_CSnshj2TYZ.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Figure 6: Task configuration. Those with an orange frame do not need to be edited, and those with a green frame are created for each task.</p>
<p dir="auto">4.2.1. <strong>init</strong> processing</p>
<ol>
<li>Creating Simulator and Environment</li>
</ol>
<p dir="auto">● create_sim: This function generates an instance of the simulator. The process itself is defined in the parent class, and the properties are set in the config file, such as gravity and step time. Similar to FrankaCubeStack, the function uses the following two functions to generate the ground plane and the actor.</p>
<p dir="auto">● create_ground_plane: This function generates a ground plane by inputting the normal direction of the plane. If you want to create an uneven terrain, you can refer to the terrain_creation example.</p>
<p dir="auto">● create_envs: This function loads and sets properties for the actor file, generates the actor and parallelizes the environment. In this task, we generated myCobot from the URDF and the target object from the create_box API. The URDF of myCobot was based on the one used in the previous experiment with MoveIt, and we added a gripper for picking (details about the gripper are explained in section 5.1).</p>
<ol start="2">
<li>Data Initialization</li>
</ol>
<p dir="auto">● init_data: This function defines environment variables from the config file and prepares a buffer for data tensors processed by Isaac Gym (PhysX). The necessary data for calculating state and reward is defined as class variables. The API loads the tensor data into the buffer, which is updated every step by calling the corresponding refresh function.</p>
<p dir="auto">4.2.2. processing steps</p>
<ol>
<li>Step Processing:</li>
</ol>
<p dir="auto">The main step function is defined in the parent class and does not need to be modified. However, the following two steps are necessary as abstract methods:</p>
<p dir="auto">● pre_physics_step: Manipulate the actor using the action. The size of the action is defined in the config as [“env”][“numActions”]. For myCobot's 6-axis arm and gripper, we set it to 7 dimensions.</p>
<p dir="auto">● post_physics_step: Calculate the observation and reward. Also check whether to reset the environment. We set it to reset after reaching a maximum of 500 steps or a successful lift.</p>
<p dir="auto">The step order is fixed to apply action → physics simulation → calculation of observation and reward to pass data for learning. Even if you only write "pass" here, you can check the environment while starting the viewer.</p>
<p dir="auto">● reset_idx: Returns the environment to its initial state. Of course, the randomness of the initial state is closely related to the generalization of learning. We set myCobot to the initial posture and randomly reset the position of the target object within myCobot's reachable range.</p>
<ol start="2">
<li>State and Reward Calculation:</li>
</ol>
<p dir="auto">● compute_observation: Update each buffer with the refresh function and put the desired state in the obs_buf. The size of obs_buf is defined in the config as [“env”][“numObservation”].</p>
<p dir="auto">● compute_reward: Calculate the reward. As the gripper approaches the target object's grip position (between the fingers), a reward is obtained, and a larger reward is obtained as the height of the target object increases.</p>
<p dir="auto">4.3. Execution of training<br />
Now that the task framework has been created, let's train the model. We can start training the model using the following command:</p>
<p dir="auto">python <a href="http://train.py" target="_blank" rel="noopener noreferrer nofollow ugc">train.py</a> task=MycobotPicking --headless<br />
After 200 epochs, the initial weights will be saved, and new weights will be saved if the reward improves. However, the task we created may not work perfectly, and the training process may stop progressing quickly. In the following section, I will discuss the adjustments I made to the task to improve its performance.</p>
<p dir="auto">4.4. Task Coordination<br />
By using the learned weights to test, you can debug why the training did not work well. You ran the command</p>
<p dir="auto">python <a href="http://train.py" target="_blank" rel="noopener noreferrer nofollow ugc">train.py</a> task=MycobotPicking test=True checkpoint=runs/MycobotPicking/nn/[checkpoint].pth<br />
to test your model. However, you encountered issues with your gripper not moving well. Despite your efforts to resolve the issue, you concluded that the URDF did not support closed-loop structures, making it difficult to simulate the gripper's movements accurately. As a result, you decided to use a rule-based approach to control the gripper's closing and lifting actions. You fixed the gripper's fingers to a fixed link and reduced the action space from 7 to 6 dimensions. You also noted that when using a simulator to control a robot arm, it is better to use a gripper without closed loops, such as the Panda arm.</p>
<p dir="auto">Another issue you faced was that the agent stopped approaching the object at a certain distance and hesitated to touch it, resulting in lower rewards. You modified the reward system by increasing the reward function's value with a threshold distance as a step function, maximizing the reward when the agent reached the target point. You also removed the environment reset after task completion, as it caused the agent to stop learning before reaching the actual goal. Instead, you adjusted the maximum number of steps to the necessary number for task completion, improving the learning speed.</p>
<p dir="auto">You also found that penalizing difficult tasks too harshly made the reinforcement learning agent too conservative. This gave the agent a more human-like personality, making the learning process more interesting. Finally, you encountered a similar phenomenon in the FrankaCabinet benchmark task, where the agent would stop learning after pulling the drawer to a certain distance, even though a higher reward was available for fully pulling it out. You did not fix this issue, but instead, you removed the environment reset after task completion and adjusted the maximum number of steps to complete the task smoothly.</p>
<p dir="auto">Figure 7: myCobot keeps away from objects</p>
<p dir="auto">The self-collision of the arm was being ignored. Although I was able to reach the desired position, the arm was now in a position where self-collision was completely ignored, like a figure-eight. I tried to research whether it was possible to set up self-collision calculation in the documentation, but it didn't work well. In the first place, it is not realistic that all joint angle limits in the provided URDF are set to -3.14~3.14, so I decided to adjust the upper and lower limits of each joint angle to avoid self-collision. The reason why the joint angles moved to the largest possible values is still unknown.</p>
<p dir="auto">Figure 8: myCobot that ignores the accident collision</p>
<p dir="auto">The arm doesn't stop exactly where it's supposed to and instead wobbles around it. We wanted the action to approach 0 as it reached the target position, but it was difficult to achieve, and the arm kept vibrating around the target position. We tried penalizing the action and adjusting the reward by setting the target position precisely, but it didn't improve the results. We decided not to worry about this issue as it could be handled by rule-based control during actual operation.</p>
<p dir="auto">Although it was not a must-have, we wanted the gripper to be downward facing for better appearance. So, we added a penalty term to the reward function that penalized the gripper angle. Figure 9 shows the learning results before fine-tuning.</p>
<p dir="auto">Figure 9: MyCobot after learning before fine-tuning</p>
<p dir="auto">The result of the adjustments mentioned above is shown in Figure 10. If this level of accuracy can be achieved on the actual robot, it should be capable of lifting objects sufficiently.</p>
<p dir="auto">Figure 10: MyCobot after training after fine-tuning</p>
<ol start="5">
<li>Others<br />
I will introduce the story that was not good and the story that I want to try.</li>
</ol>
<p dir="auto">5.1. The story of a homemade URDF gripper that didn't work<br />
The URDF of myCobot was based on the one used in the previous attempt to move the actual robot, but it did not include the gripper. Although there was a gripper model available on the official GitHub page, it only provided a DAE file with a visual representation as shown in Figure 11(a). To create a URDF that can be used in a simulator, separate 3D models for each joint part are required. Therefore, using Blender, we divided the parts by joint (Figure 11(c)) and created simplified box-shaped parts for collisions since it is difficult to reproduce complex shapes (Figure 11(b)). Then, we described the structure of the links and joints in the URDF file to complete the model. However, since URDF does not support models with open link structures, we removed the collision from one of the links on the base and completed the joint with the fingertip side. Although this method is rough, we were able to reproduce the movement of the actual robot in the simulator by moving the six joints at the same angle. Figure 11(d) shows a comparison between the completed model and the actual robot (using the provided model, but the details are quite different). However, when we actually tried to move it, as mentioned in section 4.4, it did not work well. The reason was that it was not possible to move the joints in a coordinated manner when external forces were applied (it may have been solved if torque control was properly implemented).<br />
<img src="https://hackster.imgix.net/uploads/attachments/1579038/AgAACgPnCYPTvvzVx81HE4fSP06FDMFr.png?auto=compress%2Cformat&amp;w=740&amp;h=555&amp;fit=max" alt="alt text" class=" img-fluid img-markdown" /><br />
Figure 11: Creating a gripper for myCobot (a) Published gripper model (b) Collision model parts created according to the model (c) Visual model parts disassembled from the gripper model (d) Isaac Gym Comparison of drawing and actual gripper</p>
<p dir="auto">5.2. Use image recognition<br />
In benchmarks and the MycobotPicking task, we use object position and orientation information in the observations, but obtaining this information in real-world tasks is not easy. Therefore, using only 2D camera information and easily obtainable servo joint angle information for reinforcement learning would be more valuable.</p>
<p dir="auto">We attempted to replace observations with images and use a CNN layer for learning in the FrankaCubeStack task. However, we only modified the algorithm to accept image input and as expected, the learning did not perform well. There is no framework to add the servo joint angle information as 1-dimensional data to the CNN layer, and using image information directly in the CNN layer increases the computational complexity and limits the parallelization of the environment. Additionally, we would need to tune hyperparameters such as learning rate and clip value, but we did not pursue this as the effect is not promising enough.</p>
<p dir="auto">In this test, we only confirmed the method of adding the CNN layer for learning. However, it may be more effective to use transfer learning to encode features for gripper and object recognition from easy-to-use object recognition models such as YOLO or ResNet, and then use the encoded features and joint angles for reinforcement learning, rather than using CNN layers directly with camera images.</p>
<p dir="auto">5.3. Using the Trained Model on the Actual Robot<br />
I attempted a Sim2Real experiment using the trained model and the myCobot and RealSense for spatial recognition, as mentioned in the previous article. However, it did not work well. While the reaching motion worked to some extent, the movement became unstable as it approached the object, and it was not possible to accurately move to the position to grab the object. Possible issues include the fact that the myCobot does not have enough power to move accurately to the target posture and the accumulation of small differences due to the fact that the simulator predicts the next target posture before reaching the current one, whereas the actual robot does not. Regarding the former, the myCobot used in this experiment is an inexpensive educational arm with a portable weight of 250g, so if you want to move more accurately, you should use a higher-end robot arm, such as those used in reinforcement learning for picking. Elephantrobotics, the company that makesthe myCobot, also sells models with stronger servo motors that can carry up to 1kg, so I would like to try those as well.</p>
<ol start="6">
<li>Summary<br />
This time, I created a reinforcement learning task using Isaac Gym and actually trained the model. I experienced the design of a robot reinforcement learning problem in a 3D physics simulator and the issues that arise when running the trained model. It was attractive to be able to test the learning environment without having to write the reinforcement learning algorithm from scratch. The availability of benchmark environments makes it easy to compare and verify new learning algorithms, which is a great advantage for researchers and analysts with various professional backgrounds.</li>
</ol>
<p dir="auto">ALBERT has researchers and analysts with various professional backgrounds who are ready to assist with any technical or business-related inquiries. Please feel free to contact us.</p>
<p dir="auto">Reference</p>
<ol>
<li>Tatsushi Matsubayashi, 2022.12.21, Isaac Gym で myCobot の把持タスクを強化学習してみました。</li>
</ol>
<p dir="auto"><a href="https://blog.albert2005.co.jp/2023/03/28/isaac-gym-mycobot/" target="_blank" rel="noopener noreferrer nofollow ugc">https://blog.albert2005.co.jp/2023/03/28/isaac-gym-mycobot/</a></p>
<ol start="2">
<li>ALBERT Inc. <a href="https://www.albert2005.co.jp/english/" target="_blank" rel="noopener noreferrer nofollow ugc">https://www.albert2005.co.jp/english/</a></li>
</ol>
]]></description><link>https://community.m5stack.com/topic/5213/reinforcement-learning-for-gripping-task-of-mycobot-using-isaac-gym</link><guid isPermaLink="true">https://community.m5stack.com/topic/5213/reinforcement-learning-for-gripping-task-of-mycobot-using-isaac-gym</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[UNIT MQTT: unable to set MAC address]]></title><description><![CDATA[<p dir="auto">Hi,<br />
This is a question about UNIT MQTT (SKU:U129).<br />
I sent the following AT command to change the Unit's MAC address, but an error was returned.<br />
What did i do wrong?</p>
<p dir="auto">b'AT+NETMAC=00-02-CB-12-34-56\r\n'<br />
b'+NETMAC=ERROR:Error Param\r\n'</p>
<p dir="auto">Other commands can be executed, but only the MAC address cannot be set.</p>
<p dir="auto">&lt;firmware version&gt;<br />
+VERSION=OK:1.6</p>
<p dir="auto">Thanks</p>
]]></description><link>https://community.m5stack.com/topic/5159/unit-mqtt-unable-to-set-mac-address</link><guid isPermaLink="true">https://community.m5stack.com/topic/5159/unit-mqtt-unable-to-set-mac-address</guid><dc:creator><![CDATA[shiomee]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Smart Applications of Holography and Robotic Arms myCobot 320 M5Stack-Basic]]></title><description><![CDATA[<p dir="auto"><a class="mention plugin-mentions-user plugin-mentions-a" href="https://community.m5stack.com/uid/21791">@kkkkkk</a><br />
Hi, you can click the <a href="https://www.dseelab.com/home" target="_blank" rel="noopener noreferrer nofollow ugc">link</a> to know more about it</p>
]]></description><link>https://community.m5stack.com/topic/5096/smart-applications-of-holography-and-robotic-arms-mycobot-320-m5stack-basic</link><guid isPermaLink="true">https://community.m5stack.com/topic/5096/smart-applications-of-holography-and-robotic-arms-mycobot-320-m5stack-basic</guid><dc:creator><![CDATA[ElephantRobotics]]></dc:creator><pubDate>Invalid Date</pubDate></item></channel></rss>