<?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[Wandering Ray]]></title><description><![CDATA[Hey there!]]></description><link>https://wanderingray.com</link><image><url>https://wanderingray.com/LaoShu.svg</url><title>Wandering Ray</title><link>https://wanderingray.com</link></image><generator>Shiro (https://github.com/Innei/Shiro)</generator><lastBuildDate>Fri, 03 Apr 2026 19:33:36 GMT</lastBuildDate><atom:link href="https://wanderingray.com/feed" rel="self" type="application/rss+xml"/><pubDate>Fri, 03 Apr 2026 19:33:35 GMT</pubDate><language><![CDATA[zh-CN]]></language><item><title><![CDATA[Migrating the whole backend to raspberry pi]]></title><description><![CDATA[<link rel="preload" as="image" href="https://img.wanderingray.com/notes/migrating_backend_to_rpi/WhatsApp%20Image%202026-02-17%20at%2011.34.56.jpeg"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/notes/5">https://wanderingray.com/notes/5</a></blockquote><div><p>Things are really getting easier nowadays.</p><p>2 years ago I deployed the backend of this website on a VPS, even though the backend itself is simply brought up by docker compose, I still had to do a whole bunch of nginx reverse proxy setup manually, and then paying Hetzner cloud 10 euros per month for the instance.</p><p>But finally I brought a raspberry pi 4B from home (which hasn&#x27;t been used for a long time) and setup the same system with Cloudflare tunnel, it does the job perfectly and I don&#x27;t need the VPS instance anymore</p><p><img src="https://img.wanderingray.com/notes/migrating_backend_to_rpi/WhatsApp%20Image%202026-02-17%20at%2011.34.56.jpeg" alt="I put it at the corner" height="1600" width="1200"/></p></div><p style="text-align:right"><a href="https://wanderingray.com/notes/5#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/notes/5</link><guid isPermaLink="true">https://wanderingray.com/notes/5</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Tue, 17 Feb 2026 09:37:58 GMT</pubDate></item><item><title><![CDATA[Amsterdam's "Inclusive" Children's Book: State-Sanctioned Racism Against Chinese]]></title><description><![CDATA[<div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/notes/4">https://wanderingray.com/notes/4</a></blockquote><p>Amsterdam distributed a book to 60,000 schoolchildren for its 750th anniversary. In square 42: &quot;Ni Hao! Chinese tourists block the bicycle path. To avoid them, go back to square 39.&quot;
This deliberately references the 2013 &quot;Holland&#x27;s Got Talent&quot; incident where judge Gordon mocked Chinese contestant Xiao Wang with &quot;Which number are you singing? Number 39 with rice?&quot; and called him &quot;the best Chinese I&#x27;ve had in weeks, not takeaway.&quot;
The hypocrisy is staggering. The companion book &quot;Feest in Amsterdam&quot; was criticized by Dutch politicians for being TOO inclusive - featuring Keti Koti, Eid al-Fitr, Holi festivals, and same-sex marriages. So Amsterdam celebrates Black history, Muslim holidays, Hindu festivals, and LGBTQ+ rights, but officially labels Chinese people as &quot;obstacles.&quot;
Would they DARE write &quot;Muslim/Jewish/African tourists block the path&quot;? Never. Such content would trigger immediate recalls and criminal charges. Yet anti-Chinese racism remains officially sanctioned in educational materials.
For decades, while other minorities gained protection through political correctness, Chinese communities were denied basic dignity. We&#x27;re the only group still considered acceptable targets for state-sponsored mockery.
This isn&#x27;t casual prejudice - it&#x27;s systematic indoctrination of 60,000 children, teaching them that among all ethnicities, only Chinese people deserve exclusion. The publisher&#x27;s refusal to apologize confirms it: in the West&#x27;s &quot;inclusive&quot; hierarchy, we remain at the bottom.
Amsterdam&#x27;s &quot;tolerance&quot; includes everyone - except those they reduce to takeout menu numbers.
2013 Gordon racist incident: <a href="https://www.ibtimes.co.uk/holland-talent-racist-judge-gordon-heuckeroth-refuses-525315">https://www.ibtimes.co.uk/holland-talent-racist-judge-gordon-heuckeroth-refuses-525315</a></p><p style="text-align:right"><a href="https://wanderingray.com/notes/4#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/notes/4</link><guid isPermaLink="true">https://wanderingray.com/notes/4</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Sat, 31 May 2025 17:04:29 GMT</pubDate></item><item><title><![CDATA[Defending Our Modern Life ( Translated from original speech in Chinese )]]></title><description><![CDATA[<link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/u6hs6r24mwi30o99rb.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/lx0sh152c3zifm57ib.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/jka67euwe65s036u46.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/3sst2xhe1a6sggwm5i.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/9uuv22hpm8g8i5len0.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/ymdii8yi9khhgwdmb7.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/o690ts81juk9e9fhsg.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/8xcmceecpbern3orab.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/t9fr92qz2agbgjbxqb.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/bhh7v0c6bnerzz3xyd.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/w4pxlywlsr0zr231vq.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/wi4l91rt7d7xuq880i.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/j8k2u74t13coy16iha.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/32x31ayq5hu43ca6o4.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/dllvocs8mg9x2e3aw2.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/ebtmpxe133rtja7r36.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/defeding_our_modern_life/qbsfoq1itlcs46cju0.png"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/posts/miscellaneous/Defending-Our-Modern-Life">https://wanderingray.com/posts/miscellaneous/Defending-Our-Modern-Life</a></blockquote><div><blockquote><p>Author: Ren ChongHao 任冲昊 (马平)<br/>Source: <a href="https://www.guancha.cn/MaPing/2018_01_17_443440_1.shtml">https://www.guancha.cn/MaPing/2018_01_17_443440_1.shtml</a></p></blockquote>
<h2 id="we-have-just-learned-to-eat">We have just learned to eat</h2><p>Since the release of &quot;A Bite of China&quot; in 2012, Luosifen (snail rice noodles) has become the signature dish of Liuzhou city, with Guangxi snail rice noodle shops now found throughout China. At the end of last year, National Geographic Magazine sent me to Liuzhou, Guangxi for reporting, where I specifically researched the history of Luosifen.</p><p>Regarding the origin of Luosifen, there are several local theories: some say it was invented in factory canteens as late-night meals for night shift workers; others claim it was created by food stand owners to quickly serve noodles to audiences leaving movie theaters; another theory suggests that when many travelers arrived by late-night trains needing food, shop owners only had snail soup and rice noodles left, so they improvised by combining them. The common thread in these stories is that Luosifen is definitely not an ancient food, nor was it created in home kitchens, but rather a fast food invented by modern food businesses for quick, mass production.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/u6hs6r24mwi30o99rb.png" alt="螺蛳粉 Luosifen" height="800" width="1200"/></p><p>In fact, Luosifen naturally possesses the qualities of an excellent fast food.</p><p>First, it uses dried rice noodles rather than wet ones, making the ingredients easy to transport; second, the snails are pre-cooked into the broth, providing rich flavor and oils that can be quickly reheated; third, the toppings include dried tofu skin, pickled bamboo shoots, pickled vegetables, peanuts, and a small handful of greens—most of which have a long shelf life. These advantages are quite similar to instant noodles. Therefore, Luosifen&#x27;s conquest of the national market has been achieved half through restaurant openings and half through packaged instant-style sales. Last year, the sales of packaged Luosifen from Liuzhou to the rest of China exceeded 3 billion yuan.</p><p><strong>How long has the history of such a massive industry been? As mentioned above, the market demand of modern society came first, followed by the creation of Luosifen, so its history can&#x27;t be very long. The three or four origin stories of Luosifen only trace back to the late 1970s at the earliest, making it not much older than I am.</strong></p><p>Looking at signature foods from other cities, most actually don&#x27;t have a long history either.</p><p>For example, Henan Hui Mian (braised noodles) first appeared in Zhengzhou in 1956, invented for mass production after restaurants underwent public-private partnership reforms.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/lx0sh152c3zifm57ib.png" alt="河南烩面 Henan Hui Mian (braised noodles)"/></p>
<p>Wuhan Hot Dry Noodles (Re Gan Mian) were invented around 1930. A restaurant owner who prepared semi-finished noodles daily faced a dilemma: making too few meant not having enough, while making too many caused them to stick together. His solution was to mix the noodles with oil and sesame paste. This improvisation became extremely popular and evolved into the signature dish that represents Wuhan today.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/jka67euwe65s036u46.png" alt="武汉热干面 Wuhan Hot Dry Noodles (Re Gan Mian)"/></p><p>Luosifen, Hot Dry Noodles, and Henan Hui Mian share several common characteristics: simple preparation techniques, the ability to prepare large quantities of semi-finished products in advance, and quick assembly in response to market demand. Geographically, they share another commonality—they all originated in railway hubs. Wuhan, Liuzhou, and Zhengzhou are all locations with cross-provincial railway bureaus. In 20th century China, railways were the primary mode of transportation, bringing modern society and mobile populations. This is why railway hubs were the most likely birthplaces for foods that appeal to modern tastes. The fact that Henan Hui Mian originated in Zhengzhou—a railway hub that formed in the 20th century—rather than in historical capitals like Luoyang or Kaifeng, illustrates this point clearly.</p><p>Similar to these noodle dishes are China&#x27;s four famous chicken dishes: Dezhou Braised Chicken, Henan Daokou Roast Chicken, Jinzhou Goubanzi Smoked Chicken, and Fuliqi Roast Chicken. Each corresponds to an important modern railway location. All use chicken—the most affordable meat—as their main ingredient. While their flavors differ, they all share low moisture content, portability, and long shelf life. Like Luosifen and Hot Dry Noodles, these foods are products of China&#x27;s railway era.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/3sst2xhe1a6sggwm5i.png" alt="中国人民铁路全图 1949 年 6 月 - Chinese railway map 1949 June"/></p>
<p>However, if we examine all the foods mentioned above, they share a common characteristic: a lack of fresh vegetables. Why didn&#x27;t China&#x27;s first generation of railway foods include fresh vegetables? Because vegetables and most fruits weren&#x27;t suitable for railway transport. Railways could only follow fixed routes and couldn&#x27;t efficiently collect vegetables produced in scattered locations. So while railway hubs had no shortage of mobile populations, grains, pickled vegetables, and seasonings, the supply of fresh vegetables wasn&#x27;t necessarily abundant. For China&#x27;s mobile population to enjoy delicious foods with a high proportion of vegetables at transportation hubs, they would have to wait until the highway era.</p><p>The representative food of the highway era is the Xinjiang Big Plate Chicken (Da Pan Ji) that appeared in the late 1980s and early 1990s. The correct name for this dish is Shawan Big Plate Chicken. Shawan County is situated between Urumqi on one end and Karamay on the other, connecting Xinjiang&#x27;s largest city with its major oil field.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/9uuv22hpm8g8i5len0.png" alt="克拉玛依周边公路图 - Highway map around Kramay"/></p><p>Before 2010, Karamay had no railway, so the highway traffic density in Shawan County was much higher than the national average. This enabled the county to solve vegetable transportation issues quite early. As I mentioned earlier, chicken is the most economical meat, and when combined with green peppers, potatoes, onions, and chili peppers, it creates the familiar Xinjiang Big Plate Chicken. The spread of Big Plate Chicken along highways throughout China coincided with China&#x27;s rise to become the world&#x27;s largest automobile producer.</p><p>To summarize, a significant portion of the popular foods we see on the streets today emerged only in the last few decades. The first major reason is that before the advent of railways and steamships, there wasn&#x27;t such a large mobile population to create demand, and consequently, there weren&#x27;t many restaurants or food products catering to ordinary people. Before the Opium Wars, even easily transportable items like pickled vegetables were locally produced and consumed.</p><p>After the Second Opium War, British steamships entered the Yangtze River, and modern commerce and industry emerged in Wuhan and Shanghai. With the growing mobile population, a food market formed along the Yangtze River, which led to the creation of Zhacai (pickled mustard plant). It wasn&#x27;t until 1898 that businesses in Fuling produced the first vat of Zhacai, but with the support of large markets in Shanghai and Wuhan, plus the later railway network, Fuling Zhacai had become a national fast food by 1940. Like Dezhou Braised Chicken and Hot Dry Noodles, it represents a typical food product from China&#x27;s first industrial revolution.</p><p>Another factor contributing to the emergence of numerous delicacies in recent decades is the transportation of goods. I&#x27;ve already mentioned the example of Big Plate Chicken, and here&#x27;s another: can you guess when Henan&#x27;s Wang Shou Yi Thirteen Spices appeared? It was in 1959, two years after the Wuhan Yangtze River Bridge was completed. For thousands of years, due to transportation difficulties, spices were luxury items once they left their place of origin and entered different climate zones. When the Wuhan Yangtze River Bridge connected the Beijing-Guangzhou Railway, linking northern and southern China for the first time, northern people could afford spices. This led to the emergence of affordable mixed food spices in Zhumadian, a city on the Beijing-Guangzhou line. In 1959, these spices sold for just 0.1 yuan per package—another food product created by industrialized society.</p><p>The most crucial point, however, is that people in agricultural societies weren&#x27;t in a position to be particular about food. People must first satisfy hunger before considering taste. Without sufficient grain, salt, and fats, all other delicacies become meaningless. When I started university in 1998, I had a roommate from an impoverished mountainous region who, before college, had always considered instant noodles a luxury food—simply because instant noodles quickly satisfied the need for grain, salt, and fat.</p><p>Let me give two more examples. My hometown is Pingquan in Hebei, famous for mushrooms—over 400,000 residents produce 500,000 tons of mushrooms annually. But when grain was scarce in the past, few people praised mushrooms as delicious because they&#x27;re low in calories. Who has the appetite for such things before being full? Later, I visited Yingkou City in Liaoning, where they call mantis shrimp &quot;xia pa zi.&quot; Locals told me that in the 1960s when grain was insufficient, only the poorest families would go to the seaside to gather mantis shrimp. Why did only the poor eat mantis shrimp? Because mantis shrimp have low calorie and fat content—the energy spent collecting them before being properly fed wasn&#x27;t worth it. In that era, the best delicacy was simply a combination of grain, fat, and salt, with the typical example being rice mixed with lard. Does anyone still consider this a delicacy today?</p><p>Furthermore, China&#x27;s coal production was very low then, and most rural families didn&#x27;t have stoves—only a large hearth for both cooking and heating. So even with oil, stir-frying was a luxury. Even in my childhood during the 1980s, farmers around us would only prepare stir-fried dishes when important guests were visiting.</p><p>The truly traceable folk cuisines from hundreds of years ago are mainly stewed dishes, such as Northeast China&#x27;s stewed pork with vermicelli.</p><p>One final note: there was no MSG in ancient times. The only sources of umami flavor were broths concentrated from old hens and seafood. Ordinary households and restaurants couldn&#x27;t afford such expensive seasonings. Only high-end Lu cuisine, represented by Confucius Mansion dishes, would use sufficient chicken broth and seafood to create delicacies. Most people might have gone their entire lives without experiencing umami—the taste of monosodium glutamate.</p><p>Once Chinese people became wealthier, with grain, oil, and salt widely available, and ordinary households could use gas stoves and MSG, the Chinese concept of good food became completely different from that of agricultural times. The most typical example is Sichuan cuisine replacing Lu cuisine as the mainstream cuisine on Chinese streets. This is because Sichuan cuisine uses more fire cooking, less seafood, and fewer chicken broth-based dishes, making it better suited to the cooking techniques and dietary habits of the gas stove and MSG era. Its relatively stimulating flavors also cater to the demands of ordinary people.</p><p>In fact, similar to the previously mentioned Dezhou Braised Chicken and Wuhan Hot Dry Noodles, most Sichuan dishes have also appeared only within the last century. For example, Yu-Shiang Shredded Pork, Couple&#x27;s Lung Slices, Sour and Spicy Noodles, Mala Hotpot, and Chongqing Noodles only emerged during the Republic of China period—making them younger than many people&#x27;s grandfathers here today. Dishes like Mala Xiang Guo (Spicy Numbing Stir-fry Pot) and Wanzhou Grilled Fish appeared only in the 21st century—when I was nearly finished with university. Sichuan cuisine is equally a product of modern Chinese society.</p><p><strong>Why have so many familiar Chinese foods emerged only in the last 100 years or even decades, despite China&#x27;s agricultural civilization having thousands of years of history?</strong></p><p><strong>I can answer this question using elementary school arithmetic—3,000 years of history has several dozen times the advantage over the most recent 100 years; but the total population of modern society is dozens of times larger than that of most periods in ancient times, and the proportion of people able to enjoy fine cuisine is also dozens of times higher. When these two factors of &quot;dozens of times&quot; multiply, they naturally overwhelm the single factor of &quot;dozens of times.&quot; Add to this the advancement of cooking tools, and the culinary culture accumulated by recent generations actually exceeds that of the previous several thousand years. Therefore, contemporary Chinese dietary habits are completely disconnected from agricultural society, and &quot;A Bite of China&quot; is, to a large extent, younger than even our parents.</strong></p><h2 id="the-weight-of-history">The Weight of History</h2><p>Let me expand on that arithmetic calculation to estimate our entire cultural heritage. First, I&#x27;d like to ask everyone to estimate how many people have lived on Chinese soil from the beginning of civilization to the 21st century.</p><p><strong>I don&#x27;t know this figure precisely, but I&#x27;ve seen several global estimates suggesting that approximately 80-100 billion people have been born throughout human history. Regardless of dynasty or era, Chinese civilization has consistently accounted for roughly one-fourth to one-fifth of the global population. Therefore, the total number of Chinese people throughout history is approximately 20 billion. Conversely, if we calculate based on 5,000 years of civilization with 25 years per generation, that&#x27;s 200 generations in total. Dividing 20 billion by 200 generations gives us 100 million people per generation, which is a conservative estimate at best. So the total of 20 billion is also a reasonable approximation.</strong></p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/ymdii8yi9khhgwdmb7.png" alt="How Many People Have Ever Lived On Earth? 108 Billion"/></p><p>These 20 billion people—how many have lived in New China? I have an estimate for this as well. The average life expectancy in China is over 70 years, and it&#x27;s been 69 years since the founding of the People&#x27;s Republic. Therefore, most people who were already born at the time of the country&#x27;s founding have now passed away, while most of those born after the founding are still alive. The total number of Chinese people who have lived in New China is roughly the current population plus the population at the time of founding—approximately 2 billion. Compared to the 20 billion Chinese people throughout history, that&#x27;s about a 1:10 ratio.</p><p>However, it&#x27;s obvious that the proportion of cultural creation and inheritance cannot be calculated at a 1:10 ratio. To mention just one factor, among these 2 billion people of New China, the proportion who received education is certainly an order of magnitude higher than among the previous 18 billion. And the ability to create cultural products is generally proportional to education levels. So just on education alone, these 2 billion people could match the previous 18 billion. Not to mention that modern education is far superior to that of ancient times, and modern people consume and absorb knowledge through cultural products outside of school at least ten times more than people in ancient times. Roughly estimated, New China accounts for at least half of our total cultural heritage.</p><p>I anticipate some might question my comparison, asking how ancient education can be compared to modern education. How can elementary school students today be mentioned in the same breath as Li Bai and Du Fu? Indeed, many things cannot be quantitatively compared. But I can still offer some evidence.</p><p>I currently live in Suzhou Industrial Park, an area formerly called Weiting Town, which has been culturally advanced both within Suzhou and nationally. How advanced was it? During the Daoguang period of the Qing Dynasty, this single town had its own local chronicle, with a Hanlin scholar as chief editor—its economic and cultural level was at least equivalent to an ordinary county seat in inland areas. I happened to come across this local chronicle online and extracted some poems recorded in it, which should represent high-quality works by local scholars:</p><blockquote><p>王鏊《唯亭》：
早朝时去晚朝回，陆市巴城迤逦来。咫尺唯亭看又过，人生行止信悠哉。</p><p>陈元素《送何仲先移家唯亭》：
周亲与我更芳邻，徙宅超然远市尘。路出东门船似马，湖当前岸浪如银。
谁能父子相师友，岂少贤豪互主宾。潮到此亭曾有谶，知君才不让前人。</p><p>李汾《唯亭》：
晓市争先集，唯亭水陆通。一江分上下，两庙划西东。
烟火千家爨，斜阳孤客篷。昔贤图八景，风雅有谁同。</p><p>查诜《武顺王祠》：
英姿飒爽镇三吴，日照唯亭庙貌孤。欲把美人配名将，中山祠在莫愁湖</p><p>Here are the poems mentioned:</p><p>Wang Ao&#x27;s &quot;Weiting&quot;:
Early morning I depart, late evening I return,
From Lushi and Bacheng, leisurely I come.
A short distance to Weiting, glimpsed and passed again,
Human life&#x27;s comings and goings are truly unhurried.</p><p>Chen Yuansu&#x27;s &quot;Sending Off He Zhongxian As He Moves to Weiting&quot;:
A fine neighbor becomes my fragrant companion,
Moving his home, transcendent, far from market dust.
The road out of the east gate, boats swift as horses,
The lake at the front shore, waves gleaming like silver.
Who else can have father and son as teacher and friend?
How could there be a shortage of worthy hosts and guests?
When the tide reaches this pavilion, there&#x27;s an omen fulfilled,
I know your talent will not yield to those who came before.</p><p>Li Fen&#x27;s &quot;Weiting&quot;:
At dawn the market gathers, competing to be first,
Weiting connects both water and land routes.
One river divides upper and lower,
Two temples mark west and east.
Smoke and fire from a thousand homes cooking,
Slanting sunlight on a lone traveler&#x27;s boat.
The sages of old depicted eight scenic views,
Who now shares such refined elegance?</p><p>Zha Shi&#x27;s &quot;Temple of King Wu Shun&quot;:
With gallant bearing he guards the Three Wu regions,
Sunlight illuminates Weiting&#x27;s solitary temple.
Wishing to pair a beauty with a famous general,
Zhongshan Temple stands by Lake Mochou.</p></blockquote>
<p>I&#x27;m not sure how everyone views these poems. Setting aside the literary form, I feel that their literary talent, word choice, and themes are roughly at the level of middle school students—and not even the particularly good essay writers. I believe this represents the true face of ordinary intellectuals from ancient times. The reason we perceive ancient people as having high cultural levels is that only exceptional works have been passed down through history; everyday compositions simply didn&#x27;t survive.</p><p><strong>If we must make a comparison, I previously calculated a ratio: in the late Qing Dynasty, with a population of 300-400 million, about 20,000 xiucai (entry-level scholars) were produced annually. Today, with our population of 1.3-1.4 billion, four times that of the Qing Dynasty, we produce about 70,000-80,000 domestic and foreign-educated PhDs each year—also four times the Qing figure. In other words, proportional to population, today&#x27;s PhD roughly corresponds to the ancient xiucai.</strong></p><p><strong>However, we know that xiucai represented the lowest tier of intellectuals in ancient times. 99% of them could at best be considered transmitters of culture rather than creators of new cultural achievements. Today, the situation is precisely the opposite: as a PhD, you must contribute previously non-existent knowledge to humanity through papers and experiments—in other words, every PhD is a creator of culture.</strong> There was a series of images analyzing the definition of a PhD, which I found quite fitting:</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/o690ts81juk9e9fhsg.png" alt="What does PhD mean?"/></p><p>This demonstrates that ancient society could only approach the cultural production efficiency of modern society if all intellectuals were creating culture. But what was the reality? Forget about one percent—even the most exceptional ancient intellectuals, perhaps one in a thousand, might not necessarily achieve anything that hadn&#x27;t been done before. When I suggest that the cultural accumulation of the recent 2 billion people equals that of the previous 18 billion, I&#x27;m actually being generous to our ancestors.</p><p>Let me share some more data for perspective:</p><p>Our country has a tradition where unified dynasties not only wrote histories but also collected and categorized existing books, compiling them into &quot;encyclopedias&quot; for publication—essentially summaries of cultural achievements of their time. The most famous examples include the Ming Dynasty&#x27;s Yongle Encyclopedia with nearly 400 million characters; the Qing Dynasty&#x27;s Siku Quanshu (Complete Library of the Four Treasuries) with 800 million characters; and the Gujin Tushu Jicheng (Complete Collection of Illustrations and Writings from the Earliest to Current Times) with 160 million characters.</p><p>What does 100 million characters represent? At the end of last year, Zhihu sent me some statistics showing I had written 1.6 million characters on their platform and read 98 million characters, just shy of 100 million. Of course, most of my reading was quick skimming, but this suggests that without requiring intensive study, I could read through most pre-Qing cultural heritage in about a dozen years—certainly within a lifetime. This aligns with my direct impression of the Siku Quanshu—my hometown of Chengde has the Summer Resort with the Wenjin Pavilion, which houses a complete set of the Siku Quanshu. Let me show you a photo of this building to give you an intuitive sense of the quantity of ancient cultural accumulation:</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/8xcmceecpbern3orab.png" alt="文津阁 Wenjin Pavilion"/></p>
<p>Throughout the dynasties, we&#x27;ve accumulated only this much, which reveals an important point—ancient people&#x27;s understanding of previous cultural heritage, such as Ming Dynasty people&#x27;s understanding of the Tang Dynasty, was certainly inferior to ours. Today, any historical dynasty has hundreds of dedicated researchers nationwide. For example, the Song History Research Association alone has 30-40 directors and over 500 members nationally, discussing hundreds of papers at each annual conference. This far exceeds the number of people who compiled histories in ancient times. Besides the Song people themselves, the era that understands the Song Dynasty best is now, not any of the Yuan, Ming, or Qing dynasties.</p><p>Let me give you a tangible example. In ancient times, the greatest collectors were emperors, especially those who lived long lives and liked to showcase their cultural sophistication. Qing Emperor Qianlong collected countless paintings and calligraphy works, the best of which were moved to Taiwan. However, as these collections have been gradually examined in recent decades, researchers have discovered that more than half of his Song Dynasty art pieces were fake. Even the famous &quot;Dwelling in the Fuchun Mountains&quot; scroll, preserved as an authentic piece in the imperial collection, is now largely considered inauthentic. This demonstrates that even in understanding history, ancient people were inferior to us today. Therefore, I believe that using 1900 as a dividing line, the cultural products accumulated after that date completely overwhelm the previous thousands of years in both quantity and quality.</p><h2 id="who-am-i">&quot;Who Am I?&quot;</h2><p>People are social animals, and society is constructed through cultural products such as morality and law. The cultural heritage of the entire society, as reflected in us as individuals, serves most importantly to define the concept of &quot;who I am.&quot;</p><p>Imagine being asked to introduce yourself in an unfamiliar setting. How would you do it? Obviously not with your name and ID number, but by saying you&#x27;re someone&#x27;s child, an alumnus of a certain school, a player of a particular game—that&#x27;s how you define yourself. And I, along with everyone here, share a common self-definition when facing the world—we are Chinese.</p><p>Yet this most universal definition is actually a very new concept. When my mother was young, working as a rural teacher in a mountainous area, one of the knowledge points she frequently taught was &quot;I am Chinese.&quot; For thousands of years before that, most people not only didn&#x27;t know this concept but didn&#x27;t even consider &quot;which country am I from&quot; a meaningful question.</p><p>This question encompasses two cultural backgrounds that only exist in modern society. The first is a global perspective—knowing there are other countries parallel to China in the world; the second is national consciousness—recognizing oneself as part of the country, and that national policies have clear interactions with one&#x27;s daily life. Ancient common people first didn&#x27;t understand the global situation, and second didn&#x27;t feel the country had any relationship to their lives. Changing emperors didn&#x27;t change how they lived, unless sometimes they couldn&#x27;t survive and actively sought to change emperors. Even decades later, life remained the same, so they almost never asked themselves which country they belonged to.</p>
<p>This way of life continued until the Opium War, when imperialism brought invasion to China. The traditional Confucian society and feudal warlords couldn&#x27;t resist imperialism, creating our need to establish a modern nation. On the other hand, imperialism also brought advanced technology and ideas, giving us the feasibility to establish a modern state. The most intense invasion was Japan&#x27;s in the 20th century, and the cultural concept of modern China began to form during this war. Even now, our national anthem&#x27;s lyrics state &quot;The Chinese nation faces its greatest danger,&quot; explaining why we initially needed to establish a modern country.</p><p>However, external threats only created a necessity—we had to unite, build a powerful military and developed industry to become a modern nation that imperialism would not dare invade again. But this necessity only describes the hardware of a modernized society without specifically explaining the cultural connotations of the term &quot;Chinese.&quot; We still need to answer: Who are we culturally? Why do we consider each other compatriots? Is it because of some more ancient factors?</p><p><strong>The definition of being Chinese certainly includes some ancient elements, such as Chinese characters. But many cultural symbols actually appeared quite recently, with histories similar to Sichuan cuisine.</strong></p><p><strong>For instance, the concept of &quot;Descendants of Yan and Huang&quot; was not synonymous with Chinese people before the 20th century. While Emperors Yan and Huang were important figures in the sequence of Three Sovereigns and Five Emperors, at most only some emperors and noble families claimed to have Yan and Huang bloodlines—ordinary Chinese people had no intention of acknowledging these ancestors. However, around 1900, everyone knew the Qing Dynasty was about to fall. Some revolutionaries used the identity of &quot;Descendants of Huang&quot; to inspire Han nationalism to overthrow the Qing; while other revolutionaries and reformists used the banner of &quot;Descendants of Yan and Huang&quot; to forge a Chinese nation, defining ethnic minorities as branches of Huang&#x27;s descendants, intending not only to unify Han regions but also to inherit the legacies of the Qing and previous dynasties. This is how the concept of &quot;Descendants of Yan and Huang&quot; emerged. In 1912, the first year of the Republic of China, Sun Yat-sen sent people to worship at the Mausoleum of the Yellow Emperor, establishing the precedent for modern state worship of the Yellow Emperor.</strong></p><p>When Sun Yat-sen and later the Kuomintang and Communist parties worshipped at the Yellow Emperor&#x27;s tomb, it differed from previous dynasties&#x27; practices. Earlier worship treated him as an ancient emperor and deity, not particularly distinguished from other deities or ancient emperors. When the Republic of China conducted worship at the Yellow Emperor&#x27;s tomb, they abandoned most traditional rituals from previous dynasties and specifically honored the Yellow Emperor, declaring him the ancestor of all Chinese people. This created the concept of &quot;Descendants of Yan and Huang&quot; in the 20th century. Later, during the early Anti-Japanese War period, the Kuomintang and Communist parties took turns conducting ceremonies—not out of genuine belief, but because both parties wanted to prove themselves as Sun Yat-sen&#x27;s legitimate successors with the right to lead China against Japanese aggression. In 1944, as Japan launched its final major offensive, nearly forcing the Kuomintang to abandon Chongqing, the Nationalist government still found time amid the chaos to rename what was previously Zhongbu County to today&#x27;s Huangling County, symbolizing its cultural authority as the modern state&#x27;s central government.</p><p>Besides the concept of &quot;Descendants of Yan and Huang,&quot; we also refer to Chinese people as &quot;Descendants of the Dragon (Loong).&quot; However, in ancient times, the dragon(loong) was a water deity and royal symbol, never described as the ancestor of Chinese people. It wasn&#x27;t until 1978, when the United States established diplomatic relations with mainland China, that the Kuomintang regime in Taipei felt abandoned by America and fell into confusion. Taiwanese singer Hou Dejian wanted to restate Chinese nationalism and wrote the song &quot;Descendants of the Dragon(Loong),&quot; creating this concept. In 1988, the Year of the Dragon(Loong), Hou was invited to perform this song at the Spring Festival Gala, which helped establish the concept in mainland China.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/t9fr92qz2agbgjbxqb.png" alt="《龙的传人 MV》Descendants of the Dragon(Loong) MV"/></p>
<p>This demonstrates that choosing ancestors is a rather coincidental matter. If the revolutionary parties at the end of the Qing Dynasty had chosen Yu the Great or Fuxi as progenitors, we would have a different narrative today. Yet the cultural concept of Chinese people and the Chinese nation wouldn&#x27;t fundamentally change because of this. This shows that our current definition of being Chinese doesn&#x27;t rely on these cultural symbols invented in the 20th century.</p><p>So what does the concept of &quot;Chinese&quot; really mean? I can argue this from the opposite direction:</p><p>When we insult someone, we often use the phrase: &quot;XXX, you&#x27;re not human!&quot; We all know that insults can&#x27;t change another person&#x27;s DNA—from a biological perspective, this statement is meaningless. So this phrase is actually spoken from a sociological perspective, suggesting that the other person doesn&#x27;t observe the ethical and moral baseline, such as stealing someone&#x27;s retirement savings, and thus has lost the qualification to be considered human.</p><p>Working backward from this phrase, we can see that the definition of being human comes from unified ethics and morality. The definition of being Chinese refers to your adherence to the mainstream ethics and morality of this country. We have a general consensus about what we approve of, what we oppose, what we joke about and ridicule. It&#x27;s this shared understanding that allows us to recognize each other as Chinese.</p><p>However, morality itself is attached to lifestyle. When the Anti-Japanese War ended, our country had industrial and commercial cities, traditional agricultural regions, large numbers of pastoralists, and many ethnic groups on the verge of primitive society. The regional, class, and ethnic differences were far greater than differences between many countries. So I would say that at the end of the Anti-Japanese War, the concept of &quot;Chinese&quot; culturally had only taken an embryonic form and couldn&#x27;t be said to have fully formed.</p><p>In the following decades, we first built nationally unified railway and highway networks, then worked to level income across the country as much as possible, and sent tens of millions of teachers to rural areas to establish schools. This finally popularized the concept of &quot;Chinese&quot; to a certain extent and forged a relatively unified set of values. By the 1970s, when my mother went to rural areas as a teacher, the cultural concept of &quot;Chinese&quot; was already close to being fully formed.</p><p><strong>When was the concept of &quot;Chinese&quot; or &quot;Chinese nation&quot; finally established? I believe it was between the 1980s and the early 21st century. The most important cultural event in 1980s China was the popularization of television and rural power grids. Beginning with the 1983 Spring Festival Gala, we achieved for the first time a shared cultural experience that transcended region, urban-rural divides, and social classes, with most citizens watching the same performance. From then on, each year&#x27;s Spring Festival Gala and popular TV dramas shaped a unified moral and ethical framework.</strong></p><p>Reflecting on the most memorable programs from the Spring Festival Galas of the 1980s and 1990s, apart from a few special songs, the most impressive programs that created shared language among people of the same age were those life-oriented comedy skits and crosstalk performances. These skits were meant to guide values, establish images that the state wanted us to like, and satirize what the state wanted us to dislike. At the same time, these skits also had to cater to the thinking of most viewers, avoiding major social controversies. Life-oriented TV dramas like &quot;Yearning&quot; had similar effects to the Spring Festival Gala. Even most people&#x27;s exposure to the Four Great Classical Novels began with TV adaptations that had been modified to suit modern tastes.</p><p>After more than a decade of guidance and exploration, we Chinese people formed a unified cultural ethic for the first time. We also came to believe that people from other regions would have similar ideas, so we wouldn&#x27;t feel particularly out of place working in any corner of the country. By this point, the Chinese nation had truly established itself in a cultural sense.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/bhh7v0c6bnerzz3xyd.png" alt="《渴望》"/></p><p>In the 1990s, we entered the internet age of the 21st century. The internet era essentially &quot;reviewed&quot; the concept of Chinese culture formed in the 80s-90s. In the past, television could only transmit information one-way, but now the internet is bidirectional, capable of instantly spreading netizens&#x27; thoughts. Looking at recent internet hot topics, the main content revolves around social ethics and gossip news—for example, these past few days, the hottest news has been nationwide condemnation of two families blocking doors on high-speed trains, preventing others from passing. Each time similar internet news spreads, it shapes Chinese culture and strengthens the already-formed concept of the Chinese nation.</p><p>More importantly, the information age has significantly alleviated cultural differences between social classes.</p><p>The information age has two characteristics:</p><p>First, the unit production cost of cultural products is extremely high. In the past, a small theater troupe of dozens could provide end-to-end service from scriptwriting to performance. Now the cultural industry requires cooperation among thousands or hundreds of people and investments of hundreds of millions to create movies or variety shows that appeal to the entire nation. As for cultural industry hardware, such as mobile phones, laptops, and televisions, developing a competitive brand is even more expensive—billions in investment might not be enough to fund companies like Huawei or BOE for even a month.</p><p>Second, the distribution cost of cultural products is extremely low. Regardless of whether a film costs hundreds of millions or billions to produce, if I watch a pirated version, I only need an internet connection to download it. Even going to a movie theater or watching on a video website doesn&#x27;t cost much. While phones and computers are somewhat expensive, even wage earners can afford them.</p><p><strong>This creates an effect where no matter how wealthy someone is, they can&#x27;t custom-create entirely separate cultural products and distribution platforms for themselves. For example, no matter how rich Bill Gates or Jack Ma may be, they&#x27;re unlikely to produce films based solely on their personal tastes or develop specialized phones from scratch. Meanwhile, although wage earners are less affluent, they can still afford a smartphone or movie tickets. Last summer, I interviewed DiDi&#x27;s Chairman Cheng Wei, worth billions, who, like us, plays Honor of Kings on weekends. This is unprecedented in any previous era. Despite significant class differences in our country, we haven&#x27;t experienced the degree of cultural fragmentation that existed in ancient times.</strong></p><p><strong>Under these circumstances, the unified ethical views, moral perspectives, and customs formed in the pre-internet era have actually been strengthened to some extent in the internet age. Combined with nationwide popularized &quot;hardware&quot; like Luosifen, Hot Dry Noodles, and Sichuan cuisine in recent decades, we can finally roughly describe how a typical Chinese person lives and thinks. This is what I consider the true meaning of Chinese people and the Chinese nation.</strong></p><p>When I say the concept of the Chinese nation or Chinese people was only finally formed at the end of the 20th century, it may sound sensational. But if we think carefully about it, consider when the characteristics that netizens attribute to Chinese people—such as being skilled in industry, adept at business, hardworking—were formed as self-identifications. In the mid-1980s, it wasn&#x27;t like this. At that time, from intellectuals to ordinary people, there was unanimous criticism of the nation&#x27;s small-farmer mentality, believing that we needed remedial lessons in industrial and commercial thinking. Going back several decades more, before the People&#x27;s Communes developed agricultural water conservancy projects, both Chinese and foreign newspapers consistently criticized Chinese farmers for not knowing how to farm properly, saying they weren&#x27;t as skilled in agriculture as the Japanese.</p><p>Therefore, the current substance of the Chinese nation is something formed in recent decades. Analyzing its formation process is very meaningful. In 2010, Huntington wrote &quot;Who Are We? The Challenges to America&#x27;s National Identity.&quot; Our country is much younger and weaker than the United States, so we should more frequently ask ourselves: &quot;Who is Chinese?&quot; In Water Margin, Lu Zhishen had a line before his death: &quot;As the tide comes in on the Qiantang River, today I finally know who I am.&quot; Today, I&#x27;ll adapt it as my answer to this section: &quot;As the modern tide surges forward, today we finally know who we are.&quot;</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/w4pxlywlsr0zr231vq.png" alt="水浒传 TV - Water Margin TV"/></p><h2 id="human-perception">Human Perception</h2><p>The next question is: since the concept of &quot;Chinese&quot; is largely shaped by modern society, why do most people believe it to be a tradition stretching back thousands of years?</p><p>First, it&#x27;s due to our instinctive way of thinking as humans.</p><p>From biological and anthropological perspectives, we are primates who hunted on savannas and in forests, gathering fruits—a lifestyle that continued for hundreds of thousands of years. During this extensive period, humans&#x27; ability to transform the environment was weak; we could only adapt to nature&#x27;s rhythms. Therefore, we subconsciously believe that our surroundings don&#x27;t change, and that the rules passed down from our fathers and grandfathers are the most reasonable. Those who didn&#x27;t respect existing rules would quickly be eliminated.</p><p>It was only in the last ten thousand years that we entered the agricultural age—between the first farmer and the 21st century, there are merely 300 to 400 generations. This time span is too short for fundamental changes in human genes; our brains haven&#x27;t yet adapted to a changing world. Therefore, we&#x27;re easily persuaded to believe that existing rules have been inherited for thousands or tens of thousands of years.</p><p>Secondly, there&#x27;s the issue of our human perspective.</p><p>We tend to believe that what we saw in our childhood has always existed and represents unquestionable tradition. For example, my hometown was in a mountainous region where refined grains like rice and white flour were scarce—people could only buy them with ration coupons after finding work elsewhere. Before the 1990s, the staple food for farmers was corn. When I was young, farmers in my area would scold children who didn&#x27;t study hard by saying: &quot;If you don&#x27;t get into vocational school, you&#x27;ll eat corn flour your whole life!&quot; At that time, I believed corn had been my hometown&#x27;s staple food since ancient times, representing poverty and backwardness. It wasn&#x27;t until my twenties that I accidentally heard my father mention that in the 1960s, the county sent technicians to teach farmers how to grow corn, and only then did our area&#x27;s staple food change from sorghum to corn. I was shocked to realize that corn was also a new thing for my father&#x27;s generation—a new food that tasted better and had more impact than sorghum.</p><p>Although the history of the Chinese nation is brief, it&#x27;s still long compared to our lifetimes. For the post-90s generation of internet users, these are things they&#x27;ve seen since birth. So we sincerely believe that these Chinese cultural symbols and typical Chinese lifestyles have ancient heritage.</p><p>Therefore, when facing changes, our first instinct isn&#x27;t to acknowledge development but to look to the past and find a historical model, framing change as a return to tradition. For instance, Western modern cultural development was termed the &quot;Renaissance&quot; by Westerners themselves; Wang Anshi&#x27;s reforms claimed to revive the &quot;Rites of Zhou&quot;; and in modern times, Kang Youwei&#x27;s reform proposals were written as &quot;An Examination of Confucius as an Institutional Reformer.&quot; This habitual response manifests in our personal lives when we prefer to buy so-called royal products or ancient tribute items. Merchants cater to this desire by fabricating half-true, half-false legends connecting their products to ancient emperors or famous figures.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/wi4l91rt7d7xuq880i.png" alt="《孔子改制考》 &quot;An Examination of Confucius as an Institutional Reformer&quot;"/></p>
<p>From ancient to modern society, one of our greatest changes has been the increasingly close connection between ordinary people, the state, and society. In ancient times, imperial power rarely penetrated into villages. Farmers mainly interacted with local gentry landlords and clan members. Many farmers never visited their county seat in their lifetime or had dealings with official state employees. As for national policies, they were unheard of. Conversely, farmers felt no particular loyalty to the emperor or government.</p><p>But in modern society, beginning with the French Revolution, intensifying international military and commercial competition forced each country to establish increasingly powerful and complex governments that directly mobilize every individual to participate in competition. In turn, with the development of modern industrial and commercial society and rising education levels, individuals gradually recognized how government policies affected them and began making demands of the government, requiring it to be accountable to citizens.</p><p>This close connection between individuals and government is a new phenomenon for almost all countries. Yet during the Anti-Japanese War, we had to portray it as an excellent tradition of the Chinese nation, describing it as a cultural heritage passed down from Qu Yuan and Wen Tianxiang.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/j8k2u74t13coy16iha.png" alt="京剧 - Beijing Opera"/></p>
<p>During that specific anti-imperialist period, this type of cultural shaping was effective. However, when analyzing history as case studies, we cannot fully accept these cultural tools manufactured only in the 20th century. We must recognize which elements are actually products of modernization in order to learn useful lessons from history.</p><h2 id="further-reform">Further Reform</h2><p>The Chief Architect(Deng XiaoPing) taught us that whether a cat is black or white, a good cat catches mice. Now that these 20th-century myths have played their historical role, why must I debunk them? Why can&#x27;t we simply continue claiming that these 20th-century changes came from traditional culture?</p><p>We cannot.</p><p>Because modernization isn&#x27;t a single shock wave, but a continuous process of change. If you describe cultural structures formed during the period of embracing modernization as traditional culture—as ancestral legacies that cannot be changed—you might get through current problems. But what about the next wave of reform?</p><p>Kang Youwei wrote &quot;An Examination of Confucius as an Institutional Reformer&quot; to advocate for Qing Dynasty reforms, originally positioning himself at the forefront of history. But Confucius obviously couldn&#x27;t reform institutions twice. You can use this theory for reform only once. By the next historical turning point, ideas that once drove progress become social stumbling blocks. Historically, Kang Youwei indeed became entangled in his own ideology, becoming a steadfast royalist. In 1917, when Zhang Xun attempted to restore the monarchy, Kang was one of the planners. Later, when Feng Yuxiang expelled Puyi from the Forbidden City, Kang still frequently kowtowed to Puyi. We cannot be like Kang Youwei—inventing a tradition and then becoming constrained by it, left behind by the waves of modernization.</p><p>Furthermore, clarifying these early modernization cultural transitions isn&#x27;t merely an ideological discussion—it involves breaking up interest groups. Any social structure, especially temporarily invented ones, gradually forms interest groups who are most eager to see the existing structure permanently maintained. If we don&#x27;t clarify history, interest groups can easily seize control of public opinion in the name of defending tradition, ultimately causing social development to stagnate.</p><p>Take traditional Chinese medicine, which is a mixture of empiricism and mysticism. It does contain some effective prescriptions and treatments that can be valuable when modern medical resources are insufficient. But this promotion isn&#x27;t about traditional culture—it&#x27;s part of a modern welfare system, an attempt to transform traditional medicine using modern scientific principles. By failing to clarify this and instead promoting traditional medicine in the name of carrying forward traditional culture and maintaining national pride, we&#x27;ve created a temporary myth.</p><p>By the 21st century, modern medical resources have become abundant. What should be done now is to thoroughly reevaluate traditional Chinese medicine. Each prescription and theory should undergo strict monitoring just like modern drugs before use, and every traditional medicine practitioner should first study modern medical theory before exploring effective aspects of traditional medicine. However, on one hand, we created a myth of traditional culture when promoting Chinese medicine; on the other hand, the traditional medicine industry has formed a massive interest group with significant benefits in academic circles and the pharmaceutical industry. The combination of these factors has resulted in most traditional Chinese medicine moving increasingly further from the modern medical system. Herbal medicines can be marketed without rigorous drug reviews; practitioners can open practices without attending medical school, merely by memorizing ancient texts under a master. This not only harms people but also destroys the truly effective elements of traditional medicine. This blind worship of traditional medicine is a modern myth that should be abandoned.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/32x31ayq5hu43ca6o4.png" alt="Regulation of &quot;Traditional Chinese medcine&quot; operator exams"/></p><p>Beyond traditional medicine, there are many other movements resisting change in the name of tradition, yet behind them are not genuine traditions but temporary phenomena that emerged in the early stages of modernization.</p><p>Another example is how various liquor distilleries excavate elements of &quot;alcohol culture&quot; to add historical significance to their products and defend their high-proof liquors. In reality, the vast majority of people in ancient China rarely could afford to drink alcohol, and even when they did, it wasn&#x27;t the high-proof white liquor we have today. Using tradition as justification to defend so-called alcohol culture is essentially protecting the interests of specific groups.</p><p>The issues mentioned above are at the societal level, but from a micro perspective, every family experiences conflicts between so-called tradition and modernity. Not surprisingly, most of these &quot;traditions&quot; are things formed only in recent generations. For instance, many families require children to memorize the &quot;Standards for Students&quot; (Di Zi Gui), claiming it&#x27;s traditional culture. In fact, this text was created during the final period of Confucian society and only began to circulate after the Opium War—an extremely conservative work from the eve of traditional society&#x27;s collapse, not at all a classic of traditional culture.</p><p>My family has a similar situation. I now eat more protein and fewer carbohydrates to lose weight. My mother opposes this approach, insisting that a variety of grains is most nourishing and best suited to Chinese digestive systems. However, eating grain to fullness every day is not actually a Chinese tradition—most people in agricultural society couldn&#x27;t eat their fill. My mother&#x27;s family only had enough grain to eat around the 1970s, so the &quot;tradition&quot; she uses to oppose my diet is merely a lifestyle from recent decades. If we don&#x27;t actively dispel these modern myths and blindly respect so-called traditions, modern life becomes impossible to sustain. That&#x27;s why today&#x27;s title is &quot;Defending Our Modern Life.&quot;</p><h2 id="what-do-we-do"><strong>What do we do?</strong></h2><p>Having criticized pseudo-traditions at length, now I should present a defense plan. In summary, <strong>whether genuine traditions or false ones, there&#x27;s no need for mystical halos. Most of our cultural heritage formed in the last one or two centuries. Just as we invented these cultures, we can certainly abandon them and create new ones. Even with genuine thousand-year-old traditional cultures, we must examine them carefully under modern social conditions to determine if they&#x27;re still appropriate.</strong></p><p>Specifically, I first recommend everyone learn some anthropology. When researching history and analyzing traditions, anthropology can give us courage.</p><p>Many say we should revere history, but even with reverence, human agricultural civilization spans only about ten thousand years—that&#x27;s the extent of historical research. Before that was prehistory, when humans lived as biological entities. Anthropology observes humans from both biological and cultural perspectives, so its timeline includes not just the recent ten thousand years but the hundreds of thousands or even millions of years before. When my mother insists grains are most nourishing, I can counter from an anthropological perspective that even if this is a true tradition, it&#x27;s only from the last ten thousand years—for millions of years before, we were omnivores, and specializing in certain plant seeds is actually against tradition.</p><p>From this perspective, anthropology&#x27;s main function is to dispel the sense of sanctity around the phrase &quot;since ancient times,&quot; because most sociological references to &quot;since ancient times&quot; are actually about the rules of agricultural societies. Anthropology not only covers a longer timeframe but also explores the interactions between human genetic biology and culture, uncovering patterns that may be more valuable than historical ones.</p><p>I previously read a story about Dutch colonial rule in Indonesia, where colonial officials summoned local natives and discovered that residents from more civilized agricultural regions were accustomed to bowing and kneeling, showing great deference to officials. Meanwhile, inhabitants from primitive jungle areas stood straight and didn&#x27;t consider colonial officials superior. This case demonstrates that the concept of social hierarchy isn&#x27;t an innate human tradition but rather a concept manufactured by thousands of years of class society—future societies may not necessarily have social hierarchies at all. When Marxism discusses communist society, it begins with primitive communism, not because Marx considered primitive communism admirable, but because he wanted to show us that class society is merely a product of a specific stage of human development, with no inherent legitimacy. With Marx&#x27;s way of thinking, we can truly look at history and tradition objectively.</p><p><strong>Marx&#x27;s view of history is the historical materialism we learned in school. It&#x27;s the tool we used earlier to analyze the Chinese nation and the concept of &quot;Chinese.&quot; Through this analysis, we can see through the waves of history to the essence, recognizing that most cultural symbols constituting our lives are actually products of modern society. Acknowledging this isn&#x27;t shameful—Americans have only 200+ years of history, yet they&#x27;ve led the world for the past century. Recognizing that our civilization is actually quite new doesn&#x27;t prevent us from continuing to develop. In fact, people 100 years ago already saw this clearly. Liang Qichao&#x27;s essay &quot;Young China&quot; should still be in middle school textbooks. Liang had already shed his historical baggage, and we in the 21st century shouldn&#x27;t pick it up again.</strong></p><p>Once we dispel our reverence for tradition and shed historical baggage, we can boldly invent new lifestyles to address newly emerging problems in our society. For instance, young people in big cities are reluctant to have children—they feel pressure after having one child and believe a second would impact their quality of life, causing birth rates to decline rapidly. Meanwhile, many who do have children lack the capacity to properly educate them, or even to avoid abuse. In recent years, there have been repeated news stories about children from Daliang Mountain becoming child laborers or performing in fighting exhibitions, only to leave again after being returned by the government, because their parents simply cannot provide normal schooling. In 2017, there were several news reports of parents abusing their children in public places, being reported to police by witnesses, but after police criticism and education, these irresponsible parents were allowed to take their children back home.</p><p>This series of events demonstrates that the nuclear family based on monogamy is increasingly unable to bear the full responsibility of raising children. China needs to quickly establish socialized childcare systems and revoke some parents&#x27; custody rights. Only this way can we ensure both the quantity and quality of the next generation, giving our society a future.</p><p>However, such actions would inevitably challenge the sanctity of the family, break with thousands of years of tradition, and redistribute guardianship rights away from direct relatives—certainly inviting criticism. But I believe that responsibility to the next generation is paramount. Currently, some children never have the chance to be born, while many others face problematic upbringings. Even if only considering our pension funds, we must design a new system. While family-based child-rearing may be a tradition of thousands of years, the nuclear family based on monogamy is itself a new phenomenon, widespread in China for only 30-40 years. Children needing over a decade of education to integrate into society is also a modern development. Facing these new challenges, there&#x27;s no need to maintain failing old systems in the name of tradition.</p><p>Speaking of pension funds, all of China is currently worried about the aging population problem—concerned that a high proportion of elderly people will leave no one to support them. But from my perspective, is there really an aging problem? In the past, people in their forties and fifties already had damaged teeth, skin covered in spots, and difficulty walking. Now, seventy-year-olds are everywhere, dancing in squares, shopping for groceries, with glowing skin. This is clearly rejuvenation, so how has it become a social problem?</p><p>The issue lies in the retirement age. The past retirement age of sixty was based on the nutritional levels and medical conditions of that time—sixty-year-old workers had indeed lost most of their labor capacity. Today&#x27;s sixty-year-olds are so healthy and often not doing physical labor, so they should definitely work a few more years. We&#x27;ve treated the sixty-year retirement age as too sacred and have been reluctant to change this tradition, which has created many social problems.</p><p>In conclusion, most of China&#x27;s current problems should be analyzed through the lens of historical materialism and solved with new systems. We must boldly acknowledge that social conditions have changed and that traditional experiences cannot solve most of our problems. Only then can we maintain the rapid development of recent decades. In 2014, Southern Weekend published an excellent article—the most insightful cultural commentary I&#x27;ve seen in years—I recommend everyone read it:</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/dllvocs8mg9x2e3aw2.png" alt="南方周末：《文化解码》"/></p>
<p>According to traditional thinking, &quot;establishing rites and creating music&quot; was the work of sages; today&#x27;s &quot;sages&quot; are &quot;the people,&quot; and &quot;new rites and music&quot; need to gradually form through everyday interactions among everyone, never to be forced by the cleverness of just one or two individuals. Nevertheless, when a culture places all its hope in &quot;returning to the past,&quot; it has already died.</p><h2 id="taking-initiative-making-compromises">Taking Initiative, Making Compromises</h2><p>The Southern Weekend article used the phrase &quot;establishing rites and creating music&quot; to describe our creation of new systems. I really like this description because these four characters convey a sense of taking initiative. Rather than treating problems as they arise—treating the head when the head hurts, treating the foot when the foot hurts—it suggests proactively offering comprehensive solutions. This is how modern people should approach problems. Simply put, I hope everyone will consider how society should function rather than merely criticizing existing society. If everyone only says &quot;no,&quot; the more anti-traditional we become, the more likely society will enter a state of stagnation.</p><p>For example, when a group goes out to eat, the worst scenario is when no one wants to order and everyone says &quot;whatever&quot;—the meal might never happen. Because &quot;whatever&quot; doesn&#x27;t really mean anything goes; it means &quot;you order, and I&#x27;ll reserve the right to veto if I&#x27;m not satisfied.&quot; When everyone only fights for veto power, even those with ideas become unwilling to face everyone&#x27;s criticism. In the end, everyone often has to wait until they&#x27;re starving before eating.</p><p>The United States is currently in this state where everyone says &quot;whatever.&quot; The animated series &quot;South Park,&quot; which debuted in 1997, has remained popular for 20 consecutive years.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/ebtmpxe133rtja7r36.png" alt="South Park"/></p><p>Why is it so popular? Because most Americans can find jokes they appreciate in the show. While seemingly very anti-traditional, it pokes fun at everything in society. It mocks freedom of speech but also opposes speech control; it&#x27;s against political correctness but also against political incorrectness; it ridicules others&#x27; beliefs while also mocking those who oppose religious freedom; it opposes illegal immigration while also opposing the expulsion of immigrants.</p><p>South Park represents America&#x27;s current political situation, where people from every faction don&#x27;t know what they actually want and raise their support by finding fault with others. The result? America elected Trump, one of the most ideologically conservative presidents, representing a major retreat on globalization issues. I see this as the turning point in America&#x27;s decline.</p><p>Even in decline, America remains the world hegemon and many times more prosperous than us. China&#x27;s society needs a higher development speed than America and requires far more social transformations. So while America can accept a conservative president, China must continuously pursue institutional innovation. Therefore, I hope we don&#x27;t just say &quot;no,&quot; but instead understand the operational costs of various social policies and offer constructive suggestions to society. We can&#x27;t complain about urban management officers driving away street vendors one day, calling the government&#x27;s law enforcement brutal, and then the next day, stuck in traffic, criticize the government for failing to manage even a single street properly.</p><p>As I just mentioned, when everyone only knows how to say &quot;no,&quot; the result may be that the most conservative forces end up managing society, with established interest groups benefiting the most. Many ruling groups around the world have utilized this point to manage society long-term—seizing on one or two sensitive issues to provoke public anger, uniting people in the process of opposing certain things. Citizens oppose this and that, seemingly expressing many political demands, but in the end, these demands cancel each other out, and the same people remain in power—the same interest groups from decades ago. Taiwan province has already fallen into this trap, and the mainland must not fall into such a political pitfall. We must proactively create a new system to protect our path of modernization.</p><p>Regarding China&#x27;s prospects, I&#x27;m relatively optimistic—at least compared to other countries, I have more confidence in China. Although my English isn&#x27;t strong, working in media gives me opportunities to see political discussions among foreign netizens. I feel that in terms of humanities, social sciences, and political discussions, the average depth of Chinese netizens surpasses that of any major country. I suspect this relates to our decades of materialist education, to the &quot;boring&quot; political courses we all had to take, and to China&#x27;s rapid development providing numerous sociological case studies from industrial society. Moving forward, I hope China can fully leverage this advantage and proactively build a system suitable for the productivity levels of the 21st century.</p><h2 id="industrial-confusion">Industrial Confusion</h2><p>I&#x27;ve done much rational analysis, so finally, let me share my understanding of the relationship between tradition and modernization from an emotional perspective. I know many people insist on tradition and oppose social change not just because of vested interests or firm belief in thousands of years of tradition, but because they&#x27;ve invested emotions in existing lifestyles. I say this because I myself am someone whose lifestyle changes very slowly.</p><p>I enjoy riding bicycles around, but because I learned to ride before geared bicycles were common, I still ride those straight-frame bikes from the 1980s without gears. I also prefer manual transmission when driving; whenever I drive an automatic, I keep reaching for the clutch and feel that an automatic doesn&#x27;t feel like a real car. Even when riding trains, I miss the &quot;ding-dong&quot; sounds of the old rail joints, feeling that I sleep better with the noisier wheels. When I recall my life in the 1980s and 1990s, my most immediate impressions are of warmth, beauty, and stability.</p><p>However, if you asked whether I would want to return to life in the 1980s, I would firmly say no. My rational memory tells me that compared to 2018, not only were material conditions different, but information communication levels and personal development opportunities were worlds apart. Back then, the vast majority of people were confined to their narrow living spaces, exerting all their energy to secure the most basic modern living conditions. Even those with ability and ideas couldn&#x27;t find places to showcase them. For those accustomed to the 21st century information age, the pre-internet era was essentially a large prison.</p><p>Though I clearly know the past wasn&#x27;t actually wonderful, why do I still often feel nostalgic? I ask myself this question whenever my nostalgic emotions subside. One day, I finally understood. Compared to decades ago, modern society has made many material advances, but change happens too quickly—many opportunities pass before we can grasp them. In moments of disappointment, we long for something stable to comfort ourselves, like the familiar life of our childhood. We select the beautiful aspects to slowly reminisce, experiencing the beauty of traditional life. The most typical representation of this feeling is a poem by Mu Xin:</p><blockquote>
<p>《从前慢》 木心
记得早先少年时
大家诚诚恳恳
说一句 是一句
清早上火车站
长街黑暗无行人
卖豆浆的小店冒着热气
从前的日色变得慢
车，马，邮件都慢
一生只够爱一个人
从前的锁也好看
钥匙精美有样子
你锁了 人家就懂了</p><p>&quot;Slow in the Past&quot; by Mu Xin</p><p>I remember in earlier youth
Everyone was sincere and earnest
A word said was a word meant
Early morning at the train station
Long streets dark with no pedestrians
The small shop selling soy milk steaming with warmth
In the past, daylight changed slowly
Cars, horses, mail were all slow
A lifetime was just enough to love one person
The locks of the past were beautiful too
Keys were exquisite and distinctive
When you locked it, others understood</p></blockquote>
<p>Modern people love to use this poem to praise tradition and the good old days. I admit, Mu Xin&#x27;s writing is beautiful, but with a little scrutiny, we can find contradictions.</p><p>The poem mentions railways, mail, and a soy milk shop serving early train passengers. This appears to be a small town in the mid-20th century, corresponding to Mu Xin&#x27;s youth. In his recollection, this is a stable society where small-town residents know each other, and peaceful life continues indefinitely.</p><p>However, we all know that small towns with train service and post offices—what kind of stability did they have in the 20th century? Before liberation, such towns inevitably experienced repeated wars, being occupied back and forth by the Japanese, the Northern Warlords, the Kuomintang army, and the Liberation Army. Even without war, I&#x27;m familiar with such towns—culturally completely subordinate to the nearest big city. Whatever becomes popular in the big city would be imitated here within months, and young people all want to leave. Every dozen years or so, the entire town&#x27;s appearance would change completely, becoming unrecognizable. If someone tried to freeze a small town&#x27;s life in a particular year, the first to protest would be the residents themselves, especially the young ones, because through railways and post offices they had discovered the outside world and absolutely wouldn&#x27;t resign themselves to being left behind.</p><p>Even Mu Xin himself left to explore Shanghai in his twenties and went to America in the 1980s, only returning to settle in the small town in his later years. He could live there contentedly because he had experienced the wider world and could switch between two lifestyles at will, allowing him to appreciate the town&#x27;s stable life. If he were to live his life again, I guarantee he would still go to Shanghai in his twenties and still go to America.</p><p><strong>Therefore, while nostalgia feels beautiful, it&#x27;s absolutely not a reason to abandon change. The more nostalgic we feel, the more we should seek our dreams in the future rather than being constrained by early industrialization lifestyles. Even if one day we grow old and, like Mu Xin, find a quiet place to settle down, we shouldn&#x27;t stop young people from breaking through seemingly stable lives to design a new society.</strong></p><p>On this point, I think we should all learn from Chairman Mao&#x27;s attitude. In 1966, Mao Zedong was already 73 years old—by all accounts, he could have, like Mu Xin, found a familiar place to spend his final years. However, he discovered that the great country he had established in the first half of his life was only a temporary project built on the foundation of agricultural society—a temporary project to drive away imperialism and quell warfare, not the true form of an industrialized society. In that same year of 1966, China&#x27;s industrial GDP stably exceeded agricultural GDP for the first time, and the first generation of students educated in New China had progressed from elementary school through university graduation.</p><p><img src="https://img.wanderingray.com/posts/defeding_our_modern_life/qbsfoq1itlcs46cju0.png" alt="Blue: Agricultural GDP Proportion in China; Red: Industrial GDP Proportion in China"/></p><p>Industrial productivity determines production relations. When economic development is rapid, culture and institutions must also keep pace. Currently, our society&#x27;s thinking is somewhat confused. Many people don&#x27;t understand how current social culture formed and want to move backward in the name of tradition, refusing to allow social change to keep up with our productivity development, thus affecting the modernization process. That&#x27;s why the theme of my speech today is defending modern life.</p><p>This defense of modern life contains two meanings. In the first half of my speech, I gave examples showing that most so-called &quot;traditions&quot; in society are actually new cultures invented during the modernization process. Many &quot;traditions&quot; people insist on maintaining are actually forms of modern life—we need to recognize the true face of the modernization process.</p><p>The second meaning is my hope that everyone can view history from beyond history, objectively evaluating our cultural heritage. Since traditions can be created at any time, they should also be discarded when necessary. With the development of productive forces, we will encounter countless new problems. We must create new cultural products for these new problems, allowing social institutional changes to keep pace with productivity development. Only then can we have future modern life. This modernized future is what contemporary Chinese people should value most and defend.</p></div><p style="text-align:right"><a href="https://wanderingray.com/posts/miscellaneous/Defending-Our-Modern-Life#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/posts/miscellaneous/Defending-Our-Modern-Life</link><guid isPermaLink="true">https://wanderingray.com/posts/miscellaneous/Defending-Our-Modern-Life</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Wed, 02 Apr 2025 16:51:59 GMT</pubDate></item><item><title><![CDATA[Creating FMU from OpenPLC build output with PythonFMU]]></title><description><![CDATA[<link rel="preload" as="image" href="https://img.wanderingray.com/posts/multi_lan_example/5vk26j3uk45a6i5eja.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/creating_fmu_from_openplc_build/uvqijdf8ywmzq35g0t.png"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/posts/	research/creating_fmu_via_pythonfmu">https://wanderingray.com/posts/	research/creating_fmu_via_pythonfmu</a></blockquote><div><p>The OpenPLC Editor is an IDE capable of creating programs for the OpenPLC Runtime, however it also has a graphical user interface tool for simulation/debugging of the PLC program.</p><p>When the PLC program simulation/debugging is executed in the IDE, the PLC program is compiled into a shared object (<code>.so</code>) binary file which contains the function pointers of setting and getting the traced variables.
In comparison, when the IDE generates PLC program for the runtime installed in various platforms, the end product of the compilation is a self-contained executable file, however the <code>.so</code> binary file used by the IDE simulation/debugging only contains the most minimalist function pointers for the traced variables. Therefore, for the purpose of generating FMUs, we would only need to use the <code>.so</code> binary file, which is why we&#x27;re more interested in the simulation/debugging process and how to utilize the generated <code>.so</code> binary in the IDE.</p><p><img src="https://img.wanderingray.com/posts/multi_lan_example/5vk26j3uk45a6i5eja.png" alt="The compilation in OpenPLC Editor IDE" height="664" width="835"/></p>
<h3 id="the-simulationdebugging-in-openplc-ide">The simulation/debugging in OpenPLC IDE</h3><p>The execution flow of the OpenPLC Editor&#x27;s simulation functionality (<code>_Run</code> method) can be analyzed in three main components:</p><ol start="1"><li>Runtime Loading: The system initiates PLC execution through <code>self._connector.StartPLC()</code>, which interfaces with PLCObject.py to handle the dynamic loading of the shared object (.so) binary. This represents the compiled PLC program in memory.</li><li>Debug Infrastructure: The <code>self._connect_debug()</code> method establishes the debugging framework by:
<ul><li>Initializing debug variable registration via <code>RegisterDebugVarToConnector()</code>;</li><li>Implementing a timer-based mechanism for real-time simulation monitoring;</li><li>Managing the IDE&#x27;s debugging interface</li></ul></li><li>Status Management: The system maintains state through <code>UpdateMethodsFromPLCStatus</code>, which queries the PLC status via <code>self._connector.GetPLCstatus()</code>. This creates a feedback loop between PLCObject.py and the IDE for runtime state monitoring.</li></ol><p>However the OpenPLC Editor implements an on-demand debug variable registration system, the debug infrastructure uses a subscription model where variables are only registered when actively monitored through the GUI when a user clicks the debug instance button on a variable in the POUs. In order to trace all the variables during the simulation/debugging process at the same time, and execute the simulation/debugging process without the GUI, certain changes described bellow needs to be done.</p><h3 id="modifications-to-the-openplc-ide-for-fmu-generation">Modifications to the OpenPLC IDE for FMU Generation</h3><p>To extend the capabilities of the OpenPLC IDE, I added a new feature that generates an FMU-compatible wrapper script (<code>FMUWrapper.py</code>) whenever the &quot;Start PLC Simulation&quot; button is pressed. This wrapper script integrates seamlessly with the compiled <code>.so</code> binary of the PLC program, enabling the generation of a Functional Mock-up Unit (FMU) for model exchange and co-simulation.</p><h4 id="loading-the-plc-binary">Loading the PLC Binary</h4><p>A crucial part of the <code>FMUWrapper.py</code> functionality involves dynamically loading the compiled <code>.so</code> binary of the PLC program. The binary, generated during the OpenPLC compilation process, contains the runtime logic of the PLC application.</p><p>The core function <code>_LoadPLC</code> is responsible for dynamic library loading, function pointers and debugging interfaces.</p><pre class="language-python lang-python"><code class="language-python lang-python">def _LoadPLC(self):
    md5 = open(self._GetMD5FileName(), &quot;r&quot;).read()
    self.PLClibraryLock.acquire()
    try:
        self._PLClibraryHandle = dlopen(self._GetLibFileName())
        self.PLClibraryHandle = ctypes.CDLL(self.CurrentPLCFilename, handle=self._PLClibraryHandle)
        ...
        self._startPLC = self.PLClibraryHandle.startPLC
        self._startPLC.restype = ctypes.c_int
        self._startPLC.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_char_p)]
        ...
    except Exception:
        self._loading_error = traceback.format_exc()
        return False
    finally:
        self.PLClibraryLock.release()
    return True
</code></pre>
<p>It loads the <code>.so</code> binary file dynamically into the wrapper script using <code>ctypes</code>, and the <code>dlopen</code> function on Linux platforms facilitates this step. Function pointers are extracted (e.g., <code>startPLC</code>, <code>stopPLC</code>, <code>RegisterDebugVariable</code>) from the shared library and maps them to Python-callable functions, and it also initializes debugging-related functions, such as <code>GetDebugData</code> and <code>RegisterDebugVariable</code>, allowing real-time monitoring and interaction with the PLC logic.</p><p><img src="https://img.wanderingray.com/posts/creating_fmu_from_openplc_build/uvqijdf8ywmzq35g0t.png" alt="1732792208820"/></p><p>Then we can generate the FMU by the command:</p><pre class=""><code class="">pythonfmu build -f FMUWrapper.py [projectname].so
</code></pre>
<h3 id="variable-registration">Variable registration</h3><p>A core issue when creating FMUs is how to register variables in the FMU. Typically there are 3 types of variables in FMUs: input, output and local variables, and they need to be well-defined in the modelDescription.xml file in order to be used in the simulation platforms.
However, when the C files and <code>VARIABLES.csv</code> table are generated out of the PLC program during the compilation process, the information about the variable type is not explicitly maintained, making it challenging to register the variables in the FMU.
Fortunately, these variable category information exists in the <code>plc.xml</code> file used by the OpenPLC Editor IDE as the GUI notation for the PLC program. In order to address this issue, we need to implement an xml parser to extract the variable category information from the <code>plc.xml</code> file and then use this information to register the variables in the FMU.</p><h4 id="structure-of-plcxml-and-the-variable-information">Structure of <code>plc.xml</code> and the variable information</h4><p>The <code>plc.xml</code> file is a tree-structured markup file used by the OpenPLC Ediror IDE which adheres to the PLCOpen XML format, designed for standardizing the representation of PLC programs, and in order to implement the parser to retrieve the information of the variables, we merely need to pay attention to several key elements in it.</p><h5 id="root-element-project">Root Element: <code>&lt;project&gt;</code></h5><p>The <code>&lt;project&gt;</code> element encapsulates the entire PLC program&#x27;s data. It includes attributes defining namespaces and contains child elements for metadata, data types, POU definitions, and instances.</p><h5 id="metadata-elements">Metadata Elements</h5><p><strong><code>&lt;fileHeader&gt;</code></strong> contains metadata such as the company name, product name, version, and creation date. It ensures traceability and documentation of the PLC program.</p><pre class="language-xml lang-xml"><code class="language-xml lang-xml">&lt;fileHeader companyName=&quot;Beremiz&quot; productName=&quot;Beremiz&quot; productVersion=&quot;1&quot; creationDateTime=&quot;2016-10-24T18:09:22&quot;/&gt;
</code></pre>
<p><strong><code>&lt;contentHeader&gt;</code></strong> specifies details about the project content, including scaling information for different programming languages like FBD (Function Block Diagram), LD (Ladder Diagram), and SFC (Sequential Function Chart).</p><h5 id="types-section">Types Section</h5><p>The <code>&lt;types&gt;</code> element is a repository of user-defined data types and POUs (Program Organization Units).</p><p>Data Types (<code>&lt;dataTypes&gt;</code>) could be used for defining custom or derived data types.</p><p>POUs (<code>&lt;pous&gt;</code>): The <code>&lt;pous&gt;</code> element contains multiple <code>&lt;pou&gt;</code> definitions. Each <code>&lt;pou&gt;</code> represents a POU, categorized as:</p><ul><li><code>function</code>: Represents reusable logic.</li><li><code>program</code>: Contains the main execution logic.</li><li><code>functionBlock</code>: Defines encapsulated logic blocks with internal state.</li></ul><p>For example, in the OpenPLC IDE there&#x27;s a <code>Multi_Language</code> example PLC project, where the <code>plc.xml</code> contains the <code>&lt;pou&gt;</code> node of a program organization unit called <code>&quot;plc_prg&quot;</code>, which is a <code>program</code>, the corresponding node is defined as follows:</p><pre class="language-xml lang-xml"><code class="language-xml lang-xml">&lt;pou name=&quot;plc_prg&quot; pouType=&quot;program&quot;&gt;
  &lt;interface&gt;
    &lt;inputVars&gt;...&lt;/inputVars&gt;
    &lt;outputVars&gt;...&lt;/outputVars&gt;
    &lt;localVars&gt;...&lt;/localVars&gt;
  &lt;/interface&gt;
  &lt;body&gt;...&lt;/body&gt;
&lt;/pou&gt;
</code></pre>
<h5 id="variable-definitions">Variable Definitions</h5><p>Within each <code>&lt;pou&gt;</code>, the <code>&lt;interface&gt;</code> section defines:</p><ul><li><strong>Input Variables (<code>&lt;inputVars&gt;</code>)</strong> : Variables representing external inputs to the POU.</li><li><strong>Output Variables (<code>&lt;outputVars&gt;</code>)</strong> : Variables outputting data from the POU.</li><li><strong>Local Variables (<code>&lt;localVars&gt;</code>)</strong> : Internal variables scoped to the POU.</li><li><strong>External Variables (<code>&lt;externalVars&gt;</code>)</strong> : Variables referencing external global or constant values.</li></ul><p>Each variable is defined with:</p><ul><li><code>name</code>: Identifier of the variable.</li><li><code>type</code>: Data type, such as <code>&lt;BOOL&gt;</code> or <code>&lt;INT&gt;</code>.</li><li><code>initialValue</code> (optional): Specifies a default value.</li></ul><p>For example, the variables defined in a function block named <code>CounterST</code> has a structure as follows:</p><pre class="language-xml lang-xml"><code class="language-xml lang-xml">&lt;interface&gt;
  &lt;inputVars&gt;
    &lt;variable name=&quot;Reset&quot;&gt;
      &lt;type&gt;
        &lt;BOOL/&gt;
      &lt;/type&gt;
    &lt;/variable&gt;
  &lt;/inputVars&gt;
  &lt;localVars&gt;
    &lt;variable name=&quot;Cnt&quot;&gt;
      &lt;type&gt;
        &lt;INT/&gt;
      &lt;/type&gt;
    &lt;/variable&gt;
  &lt;/localVars&gt;
  &lt;outputVars&gt;
    &lt;variable name=&quot;OUT&quot;&gt;
      &lt;type&gt;
        &lt;INT/&gt;
      &lt;/type&gt;
    &lt;/variable&gt;
  &lt;/outputVars&gt;
  &lt;externalVars constant=&quot;true&quot;&gt;
    &lt;variable name=&quot;ResetCounterValue&quot;&gt;
      &lt;type&gt;
        &lt;INT/&gt;
      &lt;/type&gt;
    &lt;/variable&gt;
  &lt;/externalVars&gt;
&lt;/interface&gt;
</code></pre>
<h5 id="body-section">Body Section</h5><p>The <code>&lt;body&gt;</code> element specifies the logic implementation of a POU using one of the IEC 61131-3 languages (structual text, function block diagram, ladder diagram etc), each type of language implementation has it&#x27;s own specific type of body element.</p><p>For example, a function block implemented in structural text would have a <code>&lt;ST&gt;</code> element that encodes logic in textual form.</p><pre class="language-xml lang-xml"><code class="language-xml lang-xml">&lt;ST&gt;
  &lt;xhtml:p&gt;&lt;![CDATA[AverageVal := INT_TO_REAL(Cnt1+Cnt2+Cnt3+Cnt4+Cnt5)/InputsNumber;]]&gt;&lt;/xhtml:p&gt;
&lt;/ST&gt;
</code></pre>
<p>Whereas a function block that has the same logic implemented by function block diagram would represent logic as interconnected blocks:</p><pre class="language-xml lang-xml"><code class="language-xml lang-xml">&lt;FBD&gt;
  &lt;block typeName=&quot;CounterST&quot; instanceName=&quot;CounterST0&quot;&gt;
    &lt;inputVariables&gt;...&lt;/inputVariables&gt;
  &lt;/block&gt;
&lt;/FBD&gt;
</code></pre>
<h5 id="instance-configuration">Instance Configuration</h5><p>The <code>&lt;instances&gt;</code> element contains the runtime configuration, defining how POUs are instantiated and scheduled.</p><pre class="language-xml lang-xml"><code class="language-xml lang-xml">&lt;instances&gt;
  &lt;configurations&gt;
    &lt;configuration name=&quot;config&quot;&gt;
      &lt;resource name=&quot;Res0&quot;&gt;
        &lt;task name=&quot;plc_task&quot; priority=&quot;1&quot; interval=&quot;T#100ms&quot;&gt;
          &lt;pouInstance name=&quot;plc_task_instance&quot; typeName=&quot;plc_prg&quot;/&gt;
        &lt;/task&gt;
      &lt;/resource&gt;
      &lt;globalVars constant=&quot;true&quot;&gt;
        &lt;variable name=&quot;ResetCounterValue&quot;&gt;
          &lt;type&gt;
            &lt;INT/&gt;
          &lt;/type&gt;
          &lt;initialValue&gt;
            &lt;simpleValue value=&quot;17&quot;/&gt;
          &lt;/initialValue&gt;
        &lt;/variable&gt;
      &lt;/globalVars&gt;
    &lt;/configuration&gt;
  &lt;/configurations&gt;
&lt;/instances&gt;
</code></pre>
<p>In the <strong><code>&lt;configurations&gt;</code></strong> element of this example, each <code>&lt;configuration&gt;</code> element groups tasks and global variables under a named resource.</p><h5 id="variable-information">Variable information</h5><pre class="language-python lang-python"><code class="language-python lang-python">{
    &quot;AverageVal&quot;: {
        &quot;input&quot;: {
            &quot;Cnt1&quot;: &quot;INT&quot;,
            &quot;Cnt2&quot;: &quot;INT&quot;,
            &quot;Cnt3&quot;: &quot;INT&quot;,
            &quot;Cnt4&quot;: &quot;INT&quot;,
            &quot;Cnt5&quot;: &quot;INT&quot;,
        },
        &quot;output&quot;: {},
        &quot;inout&quot;: {},
        &quot;local&quot;: {&quot;InputsNumber&quot;: &quot;REAL&quot;},
        &quot;external&quot;: {},
    },
    &quot;plc_prg&quot;: {
        &quot;input&quot;: {&quot;Reset&quot;: &quot;BOOL&quot;},
        &quot;output&quot;: {
            &quot;Cnt1&quot;: &quot;INT&quot;,
            &quot;Cnt2&quot;: &quot;INT&quot;,
            &quot;Cnt3&quot;: &quot;INT&quot;,
            &quot;Cnt4&quot;: &quot;INT&quot;,
            &quot;Cnt5&quot;: &quot;INT&quot;,
        },
        &quot;inout&quot;: {},
        &quot;local&quot;: {
            &quot;CounterST0&quot;: &quot;CounterST&quot;,
            &quot;CounterFBD0&quot;: &quot;CounterFBD&quot;,
            &quot;CounterSFC0&quot;: &quot;CounterSFC&quot;,
            &quot;CounterIL0&quot;: &quot;CounterIL&quot;,
            &quot;CounterLD0&quot;: &quot;CounterLD&quot;,
            &quot;AVCnt&quot;: &quot;REAL&quot;,
        },
        &quot;external&quot;: {},
    },
    &quot;CounterST&quot;: {
        &quot;input&quot;: {&quot;Reset&quot;: &quot;BOOL&quot;},
        &quot;output&quot;: {&quot;OUT&quot;: &quot;INT&quot;},
        &quot;inout&quot;: {},
        &quot;local&quot;: {&quot;Cnt&quot;: &quot;INT&quot;},
        &quot;external&quot;: {&quot;ResetCounterValue&quot;: &quot;INT&quot;},
    },
    &quot;CounterFBD&quot;: {
        &quot;input&quot;: {&quot;Reset&quot;: &quot;BOOL&quot;},
        &quot;output&quot;: {&quot;OUT&quot;: &quot;INT&quot;},
        &quot;inout&quot;: {},
        &quot;local&quot;: {&quot;Cnt&quot;: &quot;INT&quot;},
        &quot;external&quot;: {&quot;ResetCounterValue&quot;: &quot;INT&quot;},
    },
    &quot;CounterSFC&quot;: {
        &quot;input&quot;: {&quot;Reset&quot;: &quot;BOOL&quot;},
        &quot;output&quot;: {&quot;OUT&quot;: &quot;INT&quot;},
        &quot;inout&quot;: {},
        &quot;local&quot;: {&quot;Cnt&quot;: &quot;INT&quot;},
        &quot;external&quot;: {&quot;ResetCounterValue&quot;: &quot;INT&quot;},
    },
    &quot;CounterIL&quot;: {
        &quot;input&quot;: {&quot;Reset&quot;: &quot;BOOL&quot;},
        &quot;output&quot;: {&quot;OUT&quot;: &quot;INT&quot;},
        &quot;inout&quot;: {},
        &quot;local&quot;: {&quot;Cnt&quot;: &quot;INT&quot;},
        &quot;external&quot;: {&quot;ResetCounterValue&quot;: &quot;INT&quot;},
    },
    &quot;CounterLD&quot;: {
        &quot;input&quot;: {&quot;Reset&quot;: &quot;BOOL&quot;},
        &quot;output&quot;: {&quot;Out&quot;: &quot;INT&quot;},
        &quot;inout&quot;: {},
        &quot;local&quot;: {&quot;Cnt&quot;: &quot;INT&quot;},
        &quot;external&quot;: {&quot;ResetCounterValue&quot;: &quot;INT&quot;},
    },
}
</code></pre>
<h3 id="structure-of-variablescsv-and-the-variable-information">Structure of <code>VARIABLES.csv</code> and the variable information</h3><p>A typical <code>VARIABLES.csv</code> file contains 3 sections labled by a line starting with <code>//</code>: Programs, Variables and Ticktime, the <code>.csv</code> file is generated by IEC2C compiler.</p><pre class="language-python lang-python"><code class="language-python lang-python">[
    {
        &quot;num&quot;: &quot;0&quot;,
        &quot;vartype&quot;: &quot;VAR&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RESETCOUNTERVALUE&quot;,
        &quot;C_path&quot;: &quot;CONFIG__RESETCOUNTERVALUE&quot;,
        &quot;type&quot;: &quot;INT&quot;,
        &quot;derived&quot;: &quot;INT&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    {
        &quot;num&quot;: &quot;1&quot;,
        &quot;vartype&quot;: &quot;FB&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RES0.PLC_TASK_INSTANCE&quot;,
        &quot;C_path&quot;: &quot;RES0__PLC_TASK_INSTANCE&quot;,
        &quot;type&quot;: &quot;PLC_PRG&quot;,
        &quot;derived&quot;: &quot;&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    {
        &quot;num&quot;: &quot;2&quot;,
        &quot;vartype&quot;: &quot;VAR&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RES0.PLC_TASK_INSTANCE.RESET&quot;,
        &quot;C_path&quot;: &quot;RES0__PLC_TASK_INSTANCE.RESET&quot;,
        &quot;type&quot;: &quot;BOOL&quot;,
        &quot;derived&quot;: &quot;BOOL&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    {
        &quot;num&quot;: &quot;3&quot;,
        &quot;vartype&quot;: &quot;VAR&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RES0.PLC_TASK_INSTANCE.CNT1&quot;,
        &quot;C_path&quot;: &quot;RES0__PLC_TASK_INSTANCE.CNT1&quot;,
        &quot;type&quot;: &quot;INT&quot;,
        &quot;derived&quot;: &quot;INT&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    {
        &quot;num&quot;: &quot;4&quot;,
        &quot;vartype&quot;: &quot;VAR&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RES0.PLC_TASK_INSTANCE.CNT2&quot;,
        &quot;C_path&quot;: &quot;RES0__PLC_TASK_INSTANCE.CNT2&quot;,
        &quot;type&quot;: &quot;INT&quot;,
        &quot;derived&quot;: &quot;INT&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    {
        &quot;num&quot;: &quot;5&quot;,
        &quot;vartype&quot;: &quot;VAR&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RES0.PLC_TASK_INSTANCE.CNT3&quot;,
        &quot;C_path&quot;: &quot;RES0__PLC_TASK_INSTANCE.CNT3&quot;,
        &quot;type&quot;: &quot;INT&quot;,
        &quot;derived&quot;: &quot;INT&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    {
        &quot;num&quot;: &quot;6&quot;,
        &quot;vartype&quot;: &quot;VAR&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RES0.PLC_TASK_INSTANCE.CNT4&quot;,
        &quot;C_path&quot;: &quot;RES0__PLC_TASK_INSTANCE.CNT4&quot;,
        &quot;type&quot;: &quot;INT&quot;,
        &quot;derived&quot;: &quot;INT&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    {
        &quot;num&quot;: &quot;7&quot;,
        &quot;vartype&quot;: &quot;VAR&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RES0.PLC_TASK_INSTANCE.CNT5&quot;,
        &quot;C_path&quot;: &quot;RES0__PLC_TASK_INSTANCE.CNT5&quot;,
        &quot;type&quot;: &quot;INT&quot;,
        &quot;derived&quot;: &quot;INT&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    {
        &quot;num&quot;: &quot;8&quot;,
        &quot;vartype&quot;: &quot;FB&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RES0.PLC_TASK_INSTANCE.COUNTERST0&quot;,
        &quot;C_path&quot;: &quot;RES0__PLC_TASK_INSTANCE.COUNTERST0&quot;,
        &quot;type&quot;: &quot;COUNTERST&quot;,
        &quot;derived&quot;: &quot;&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    {
        &quot;num&quot;: &quot;9&quot;,
        &quot;vartype&quot;: &quot;VAR&quot;,
        &quot;IEC_path&quot;: &quot;CONFIG.RES0.PLC_TASK_INSTANCE.COUNTERST0.EN&quot;,
        &quot;C_path&quot;: &quot;RES0__PLC_TASK_INSTANCE.COUNTERST0.EN&quot;,
        &quot;type&quot;: &quot;BOOL&quot;,
        &quot;derived&quot;: &quot;BOOL&quot;,
        &quot;retain&quot;: &quot;0&quot;,
    },
    .....
]
</code></pre>
<p>Now the naming convention of the IEC_PATH is quite unclear from the output.</p><p>iec_types</p><h3 id="parsing-variablepou-connections-from-plcxml">parsing variable/pou connections from plc.xml</h3><p>Since the generated <code>VARIABLES.csv</code> lost the information of the &quot;connections&quot; between the variables, another task is to parse the <code>plc.xml</code> directly and map the variables to the ones in <code>VARIABLES.csv</code>. 
And in <code>ProjectController.py</code> the variables in <code>VARIABLES.csv</code> is already parsed into <code>self._VariablesList</code> in <code>GetIECProgramsAndVariables(self)</code>, all of the xml variable mapping work is done in <code>VariableMapper.py</code>.</p><h3 id="example-of-generated-fmuwrapperpy">Example of generated FMUWrapper.py</h3><p>here&#x27;s one of the <code>FMUWrapper.py</code> generated from the plc program:</p><pre class="language-python lang-python"><code class="language-python lang-python">def _register_fmu_variables(self):
        # set traceList

        self.traceIdxList.append((0, &quot;SIN2TAN&quot;, None))
        self.variable_unpack_list.append((0, &quot;CONFIG0.RES0.INSTANCE0&quot;, &quot;SIN2TAN&quot;))

        self.traceIdxList.append((1, &quot;REAL&quot;, None))
        self.variable_unpack_list.append((1, &quot;CONFIG0.RES0.INSTANCE0.SINEVALUE&quot;, &quot;REAL&quot;))

        self.traceIdxList.append((2, &quot;REAL&quot;, None))
        self.variable_unpack_list.append((2, &quot;CONFIG0.RES0.INSTANCE0.TANGENTVALUE&quot;, &quot;REAL&quot;))

        self.traceIdxList.append((3, &quot;REAL&quot;, None))
        self.variable_unpack_list.append((3, &quot;CONFIG0.RES0.INSTANCE0.COSINEVALUE&quot;, &quot;REAL&quot;))

        #register fmu variables

        self.INSTANCE0__SINEVALUE = 0.0
        self.fmuTraceVarList.append(&quot;INSTANCE0__SINEVALUE&quot;)
        self.register_variable(Real(&quot;INSTANCE0__SINEVALUE&quot;, causality=Fmi2Causality.input, variability=Fmi2Variability.continuous, initial=Fmi2Initial.exact, start=0.0))
        self.fmu_variable_unpack_list.append((1, &quot;INSTANCE0__SINEVALUE&quot;, &quot;REAL&quot;))

        self.INSTANCE0__TANGENTVALUE = 0.0
        self.fmuTraceVarList.append(&quot;INSTANCE0__TANGENTVALUE&quot;)
        self.register_variable(Real(&quot;INSTANCE0__TANGENTVALUE&quot;, causality=Fmi2Causality.output, variability=Fmi2Variability.continuous, initial=Fmi2Initial.calculated))
        self.fmu_variable_unpack_list.append((2, &quot;INSTANCE0__TANGENTVALUE&quot;, &quot;REAL&quot;))

        self.INSTANCE0__COSINEVALUE = 0.0
        self.fmuTraceVarList.append(&quot;INSTANCE0__COSINEVALUE&quot;)
        self.register_variable(Real(&quot;INSTANCE0__COSINEVALUE&quot;, causality=Fmi2Causality.local, variability=Fmi2Variability.continuous, initial=Fmi2Initial.calculated))
        self.fmu_variable_unpack_list.append((3, &quot;INSTANCE0__COSINEVALUE&quot;, &quot;REAL&quot;))
</code></pre><p>The trace list part is just the variables from <code>VARIABLES.csv</code>, and bellow are the variables mapped from both <code>plc.xml</code> and <code>VARIABLES.csv</code>.</p><h3 id="generating-fmu-using-pythonfmu">Generating FMU using PythonFMU</h3><p>Eventually, I use a command to generate fmu out of <code>FMUWrapper.py</code> and other files like this:</p><pre class=""><code class="">pythonfmu build -f FMUWrapper.py *.so *.dll lastbuildPLC.md5 requirements.txt runtime/ serial/
</code></pre><p>here the <code>*.so</code> and <code>*.dll</code> are the binaries built from PLC program, FMUWrapper is what generated from the build process (due to all my modifications to the IDE), <code>runtime/</code>  is the openPLC IDE&#x27;s implementation of the runtime used for interaction with the binaries, and <code>serial/</code> is a third-party package required here.</p></div><p style="text-align:right"><a href="https://wanderingray.com/posts/	research/creating_fmu_via_pythonfmu#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/posts/	research/creating_fmu_via_pythonfmu</link><guid isPermaLink="true">https://wanderingray.com/posts/	research/creating_fmu_via_pythonfmu</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Thu, 06 Mar 2025 17:45:04 GMT</pubDate></item><item><title><![CDATA[Why I Hate "Obedience"  (听话)]]></title><description><![CDATA[<div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22">https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22</a></blockquote><div><p>After a year and a half, I finally went back to my hometown for 2 weeks. My grandmother&#x27;s 90th birthday happened to be during this week, so a group of relatives came over, mainly my uncle, aunt, and her sisters who work in Shenzhen.<br/>To get straight to the point, I’ve always disliked talking to them since I was young. While my mom would sometimes chime in during their conversations, I would usually stay silent and keep my focus on the TV, only responding when the topic was directed at me. One reason for this is that my mom and grandmother often warned me to be cautious with my words while talking to them, as my uncle, aunt, and their relatives are highly superstitious. Saying anything they deemed &quot;unlucky&quot; would upset them.<br/>Thinking about it, this reason alone didn’t fully explain my reluctance to engage with them. But after this recent visit, I finally understood.<br/>The thing I hate the most during these family gatherings is the endless comparison of their children—where their kids are studying, what jobs they have, etc. They claim to be &quot;caring about the younger generation,&quot; but anyone who talks to them for more than a few minutes would realize this is a shallow excuse.<br/>For example, during dinner, the conversation turned to my cousin who had just landed a government job. The relatives eagerly started planning her career for her—moving back home, marrying a nice guy, and so on.<br/>I said, &quot;Wait, shouldn’t these decisions ultimately depend on my cousin’s own wishes? How do you know what she wants or plans?&quot; Aunt B replied, &quot;It’s okay, she’s obedient.&quot;<br/>This statement just made me feel sick. Later, when they praised me for being &quot;obedient,&quot; I cut them off, &quot;I hate it when you say I’m ‘obedient.’&quot; Aunt B retorted, &quot;Fine, we won’t say you’re ‘obedient.’ We’ll say you’re ‘bad,’ happy now?&quot;<br/>I couldn’t be bothered to continue the conversation. That’s when I realized why I despised talking to them—because it was a pointless effort when they neither respected me nor had any intention of truly engaging. The worst part was, they were completely oblivious to it.</p><p>At this point, if you’re not familiar with the meaning of &quot;obedient&quot; (听话) in the Chinese or East Asian cultural context, you might be confused. I&#x27;ll try to elaborate. In this context, &quot;obedient&quot; usually refers to children being submissive and compliant to parents, teachers, or elders, showing no resistance or defiance. It implies that the child acts according to the expectations set by adults, follows the rules, and does not challenge authority. In simple terms, &quot;obedient&quot; represents an image of being well-behaved and sensible, embodying the traditional virtues of respecting and adhering to authority.<br/>However, that’s not the main issue. The real problem lies in the fact that, at least before the Industrial Revolution, China’s society was largely unchanged for thousands of years, making &quot;obedience&quot; an effective survival strategy in a feudal, agrarian context.<br/>But what does that have to do with us today? The issue is, I realized my relatives are deeply rooted in these beliefs:</p><ul><li>A: They are older and have rich life experience.</li><li>B: They are successful (regardless of their own definitions, they’re wealthy, and in their eyes, wealth is the sole measure of success). They believe their success is due more to A than to luck (A =&gt; B).</li><li>C: The younger generation will be successful if they follow their guidance.<br/><br/>It’s pretty damn obvious that their logic is totally bullshit. Even without pointing out these logical fallacies, expecting the younger generation to follow their outdated perspectives is foolish and irresponsible. I strongly believe in the balance of rights and responsibilities. These elders want to make life decisions on behalf of the younger ones without being willing or able to bear the consequences. Considering their understanding and experiences are likely out of touch with current realities, letting them dictate the lives of the younger generation is absurd. In other words, blindly being &quot;obedient&quot; is a sign of irresponsibility towards one’s own life.<br/>We live in an ever-changing world, and with billions of people on this planet, encountering different viewpoints is normal. What disgusts me most about my relatives is that when they hear opinions different from theirs or when I disagree with them, they have no interest or patience to listen to my reasoning. They can’t even sit through a five-minute explanation without interrupting, showing complete disrespect for me.<br/><br/>In conclusion, their behavior serves as a reminder for me of what not to become.</li></ul></div><p style="text-align:right"><a href="https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22</link><guid isPermaLink="true">https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Tue, 29 Oct 2024 17:38:22 GMT</pubDate></item><item><title><![CDATA[我为什么痛恨”听话“]]></title><description><![CDATA[<div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22-cn">https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22-cn</a></blockquote><div><p>时隔一年半，我终于又回老家住了一两周。正好外婆也在这周过 90 岁的生日，所以一群亲戚也来了，主要是一直在深圳工作的舅舅、舅妈以及舅妈的姐妹们。<br/>单刀直入地说，我印象中我从小就非常讨厌和他们交谈，基本上他们再说话的时候妈妈还会时不时随声附和一下，但我就基本全程闭嘴把注意力放在电视节目上，只有当他们突然把话题转换到我身上或者明确对着我说话的时候我才会做出回应。当然这也有很多原因，比如妈妈和外婆就经常告诫我在和他们聊天的时候必须要时刻注意用词， 因为显然大舅舅和大舅妈以及他们的亲戚（不知道为什么）都是非常迷信的人， 如果说出一些他们认为“不吉利”的话会惹他们不高兴。<br/>仔细想想，单拿出这个原因好像也没办法解释为什么我会这么厌烦跟他们聊天。不过这次回来碰见他们之后我终于明白了。<br/>话说回来， 每次回家碰到这种格律亲戚聚到一起的场景，最让我痛恨的事情就是这帮人总是要永无止境地拿自己的小孩来互相攀比——什么你的小孩又到哪上学啦，我的小孩又找到了个什么工作啦——虽然他们美其名曰“关心年轻一代”， 但其实只要和他们多聊两句就不难发现这套说辞完全就是狗屁不通的借口和鬼话。<br/>比如说，晚餐时间在饭桌上谈论起我的表妹终于幸运考上了公务员， 这帮亲戚们就忙不迭地给她规划起职业生涯来了， 什么想办法调回老家啦，找个老实好男人嫁了之类的。<br/>我说：“不是，你们搁这讨论半天，但归根结底这些事情肯定得取决于表妹自己的想法啊？你们怎么知道她想要什么， 有什么计划呢？“ 结果阿姨B直接回答：”没关系， 她很听话的“。<br/>这种发言让我直犯恶心，后来他们对着我妈妈夸赞我是如何听话的时候，<strong>我直接打断他们：“我非常反感你们说我‘听话’。“ 阿姨B就回答说：”行， 不说你‘听话’了，说你‘坏’， 满意了吧？“</strong><br/>我已经懒得跟他们继续聊下去了。这个时候我突然明白了自己为什么如此痛恨和这帮人交流， <strong>因为在他们对我毫无尊重而且更没有任何交流意愿的前提下这完全就是白费力气，更离谱的是他们竟然对此毫无自觉</strong>。<br/>看到这里， 如果您对汉语或者汉语/东亚文化语境中‘听话’的涵义不太了解，您可能会觉得云里雾里，我得先来解释下在我们的语境中‘听话’是什么意思。在汉语文化圈的语境下，“听话”通常指孩子对家长、老师或长辈的顺从和服从，表现出不反抗、不顶撞的行为。这意味着孩子按照家长的要求行事，遵循他们设定的规矩，不轻易质疑或违背权威。简单来说，“听话”代表一种乖巧、懂事的形象，是父母期待的表现方式，象征着尊重和服从权威的传统美德。<br/>可实际上这并不是问题的关键，因为实际上至少在工业革命以前，中国作为一个拥有数千年悠久历史的文明其实在封建农耕时代的社会形态很大程度上可以说是一成不变的，因此‘听话’确实是一种非常高效的生存策略。<br/>但那都是以前，跟我们现代人有什么关系？ 要命的是，我发现我的这群亲戚根深蒂固地相信以下几点：</p><ul><li>A: 他们年纪很大， 对社会有丰富的经验;</li><li>B: 他们事业有成（先不管他们自己是怎么定义的，反正他们很有钱，基本上大致可以认为在他们的观念中“有钱与否”这个单一维度就是衡量是否成功的唯一标准）， 而他们认为自己的成功比起运气好更多的应该归功于A ( A =&gt; B );</li><li>C: 年轻一代只要遵从他们的指导， 就一定能向他们一样成功。
不难发现他们的逻辑纯属狗屁不通。就算不谈他们的逻辑缺陷， 要求年轻一代遵从他们根据自身认知做出的安排本身就是极其愚蠢和不负责任的。我非常讲究权利和义务的对等，这些长辈们一边要代替晚辈来行使做出人生决定的权利，一边有不愿意/没有能力为晚辈们承担任何的后果，考虑到他们的认知和经验极有可能已经不符合当下社会的现实，放任他们去操控晚辈的人生是非常不可理喻的。也就是说年轻人如果一直“听话”， 实际上也是对自己的人生不负责任的表现。<br/>我们生活在一个瞬息万变的时代，再加上全世界有几十亿人， 遇到和自己有不同观点与看法的人其实是很正常的。但这帮亲戚最让我恶心的是，当他们听到我有和他们不一样的观点或者不同意他们的看法时， 他们完全没有兴趣和耐心听我解释我为什么会产生这些不一样的观念，甚至没办法做到安安静静地听我做一个 5 分钟左右的观点论述就要急着打断， 这已经体现出了他们对我毫无尊重。<br/>总而言之，他们的样子也是我对自己的一个警示：不要成为这样的人。</li></ul></div><p style="text-align:right"><a href="https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22-cn#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22-cn</link><guid isPermaLink="true">https://wanderingray.com/posts/miscellaneous/Why-I-Hate-%22Obedience%22-cn</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Tue, 29 Oct 2024 17:36:37 GMT</pubDate></item><item><title><![CDATA[Multiple Language Example in OpenPLC]]></title><description><![CDATA[<link rel="preload" as="image" href="https://img.wanderingray.com/posts/multi_lan_example/dq3ekp4g6dka3ov0v5.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/multi_lan_example/iro21vq79y00sfcnhk.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/multi_lan_example/5vk26j3uk45a6i5eja.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/multi_lan_example/xyxim35l0smv21m9w0.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/multi_lan_example/evvy3l0z39un0ntu2p.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/multi_lan_example/t9babi027iyfpxiaiv.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/multi_lan_example/6v1359muwfyycci76j.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/multi_lan_example/iq3mnrtlpk5ua24fin.png"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/posts/	research/multiple_language_example_in_OpenPLC">https://wanderingray.com/posts/	research/multiple_language_example_in_OpenPLC</a></blockquote><div><h3 id="previous-problems">Previous problems</h3><ol start="1"><li>Is the compiled .so library files able to be executed on actual devices? Is it executed well in local simulator / development runtime environment?</li><li><strong>(When the OpenPLC editor is running the simulation of the PLC program) How is the simulation process executed?</strong> Understanding this could be extremely crucial for creating FMU for OSP sw. (TODO: Look into OpenPLC runtime)</li><li>How exactly is the compilation process executed? Is it possible to expose some internal variables or input to external entities? To what degree is the whole program configurable?</li><li><strong>What are the possible limits for PLC programs ( if the developers want to create FMUs for these programs )? For example if some variables are supposed to be accessible by external entities rather than being private withing the FMU, would there be a guideline / to-do / not-to-do list for for the PLC programs?</strong></li></ol><p><strong>And more importantly, it could be helpful to take a look into the the simulation functionalities that comes with the OpenPLC development tool, how does it work,  what is simulated and what is not, the limitations, and more importantly how exactly is it implemented.</strong></p><h3 id="different-languages-in-iec-61131-3-with-example">Different languages in IEC 61131-3 with example</h3><p>Previously we looked at a example that runs on Arduino written by ladder diagram PLC programming langrage, and it brings several questions:</p><ol start="1"><li>We&#x27;re not sure which language is more preferred to the users.</li><li>Is there any difference in the generated C code between PLC programs written in different IEC 61131-3 languages? If that&#x27;s the case, what are the potential limitations and drawbacks we need consider when attempting to create FMUs for them?</li></ol><p>Fortunately, there&#x27;s another example in OpenPLC editor that are composed of several units written in different IEC 61131-3 languages, and it would be easier to examine how the building blocks are composed and how they are interacting with each other in this example that contains Program Organization Units ( POUs ) in different languages.</p><h3 id="the-compile-process-of-plc-programs-in-openplc">The compile process of PLC programs in OpenPLC</h3><p>OpenPLC editor uses a fair amount of legacy code of another open source PLC development tool called Beremiz ( which is also an IDE for PLC programs in IEC 61131-3 languages, and it also uses the PLC open editor and MatIEC compiler to translate the PLC programs into ANSI C code ), there&#x27;s a more detailed compilation process of the PLC program from Beremiz&#x27;s documentation.</p><h4 id="plcopen-xml-project-beremizxml-and-plcxml">PLCOpen XML project (<code>beremiz.xml</code> and <code>plc.xml</code>)</h4><p>These are the initial 2 files used by the PLC open editor. The editor would save and load the PLC programs using XML markup files ( in this case <code>plc.xml</code> ) according to <a href="https://plcopen.org/system/files/downloads/tc6_xml_v201_technical_doc.pdf">PLCopen TC6-XML Schemes</a> [2].<br/><img src="https://img.wanderingray.com/posts/multi_lan_example/dq3ekp4g6dka3ov0v5.png" alt="PLCOpen Editor and XML" height="597" width="1520"/></p><p> &quot;PLCOpen Editor and XML, source: <a href="https://beremiz.org/doc">https://beremiz.org/doc</a>&quot;
The PLCOpen XML project files may not exactly correspond to the DOM (Document Object Model) in web development terms, the XML files store a textual representation of the graphical PLC programs( such as the coordinate system and positions of the graphical components ), and they serve as an intermediate format that OpenPLC can interpret and manipulate.
<img src="https://img.wanderingray.com/posts/multi_lan_example/iro21vq79y00sfcnhk.png" alt="PLCOpenDatamodel to IEC61131-3 languages"/><br/>The PLC open editor can parse the XML file back to the graphical representations, meanwhile it also has built-in export filter that convert graphical languages to their equivalent textual form.</p><h4 id="plcopen-tc6-xml-xml-schema">PLCOpen TC6-XML XML Schema</h4><p>However, the parsing process itself doesn&#x27;t guarantee the correctness of the PLC program. The schema is the constrain which ensures the XML-documents are compiled in a certain well-define manner.</p><h4 id="plcopen-data-model">PLCOpen Data Model</h4><h4 id="xslt-extensible-stylesheet-language-transformations">XSLT (eXtensible Stylesheet Language Transformations)</h4><h5 id="purpose">Purpose</h5><p>XSLT is used to transform XML documents into other formats or different XML structures. For example, if there is an XML file in a format specific to a vendor, an XSLT stylesheet can be applied to transform that XML into the PLCopen standard XML format used by OpenPLC. This process ensures compatibility between different PLC programming environments.</p><h4 id="iec-to-c-compilation-matiec">IEC to C compilation (MatIEC)</h4><p><img src="https://img.wanderingray.com/posts/multi_lan_example/5vk26j3uk45a6i5eja.png" alt="Compilation from IEC61131-3 to C program"/><br/>The MatIEC works this way:</p><ul><li>Compiles ST/IL/SFC code into ANSI-C code.</li><li>All POU parameters and variables are accessible through nested C structs</li><li>Located variables are declared as extern C variables</li></ul><h4 id="an-overview-to-pou-program-organization-unit">An overview to POU (Program organization unit)</h4><p>A Program Organization Unit (POU) is a fundamental concept in IEC 61131-3, one important goal of the IEC 61131-3 standard is to introduce and restrict the terminologies which referred to the building blocks of a PLC programs. POUs are the basic building blocks of a PLC program, allowing modularity, reusability, and better organization of the control logic. [4]</p><p>In the IEC-61131-3 standard, there are three types of POUs: <strong>Programs (PRG)</strong>, <strong>Function Blocks (FB)</strong> and <strong>Functions (FUN)</strong>.</p><h5 id="function-fun">Function (FUN)</h5><p>Functions are reusable logic components that return a single value and do not retain internal state between execution cycles.They are used for small, stateless operations, such as mathematical calculations (e.g., addition, subtraction) or boolean logic (e.g., AND, OR). Functions don&#x27;t retain any internal state, which also means that they are guaranteed to generate identical output by providing same input.</p><h5 id="function-blocks-fb">Function Blocks (FB)</h5><p>A function block is a reusable POU that has internal state memory, meaning it can store values between cycles.
Function Blocks are similar to classes in object-oriented programming. They encapsulate specific control behaviors (like a timer, counter, or PID controller) and can be instantiated multiple times within a program or across different programs.
<strong>Unlike simple functions, function blocks have internal memory, meaning that they can retain values (such as timer values or counters) between execution cycles.</strong> This allows them to handle operations that need to maintain state, such as accumulating values over time.
In the following <code>Multi_Language</code> example in OpenPLC editor, all the function blocks named <code>Counter%%%</code> have their local (internal) variable called <code>Cnt</code>, which retains the state of the execution in each loop.</p><h5 id="programs-prg">Programs (PRG)</h5><p>The main unit where the control logic resides. A program is what the PLC executes cyclically (or triggered based on conditions) during its operation.
The program is the top-level POU and is often where the primary control logic of the system is implemented. A program can call other POUs like Functions (FUN) and Function Blocks (FB).</p><table><thead><tr><th> POU Type                      </th><th> Retains State </th><th> Reusability </th><th> Example Use Case                         </th></tr></thead><tbody><tr><td> <strong>Program (PRG)</strong>       </td><td> No            </td><td> Main logic  </td><td> Overall system logic or control sequence </td></tr><tr><td> <strong>Function Block (FB)</strong> </td><td> Yes           </td><td> Reusable    </td><td> Timer, Counter, PID controller           </td></tr><tr><td> <strong>Function (FUN)</strong>      </td><td> No            </td><td> Reusable    </td><td> Math operations, Logical comparisons     </td></tr></tbody></table><h5 id="how-pous-work-together">How POUs work together</h5><p><strong>Programs (PRG)</strong> call Function Blocks (FB) and Functions (FUN) to implement control logic.
A <strong>Function Block (FB)</strong> can be used to manage operations that need to store internal states, like a timer or a motor control routine.
<strong>Functions (FUN)</strong> perform stateless operations like mathematical calculations or logical comparisons.</p><h3 id="multilanguage-example"><code>Multi_Language</code> example</h3><p>Here is the structure of the this <code>Multi_Language</code> example project:<br/><img src="https://img.wanderingray.com/posts/multi_lan_example/xyxim35l0smv21m9w0.png" alt="Multi_Language project structure"/><br/>There&#x27;s several building blocks here:</p><ol start="1"><li><code>AverageVal</code> : this is a <strong>Function (FUN)</strong> written in  structural text;</li><li><code>Function Blocks</code> : this is a collection of several Function Blocks (FB) written in different languages;</li><li><code>plc_prg</code> : this is the Program (PRG) that integrates the above building blocks to perform the control logic. <strong>In terms of the hierarchy, this could also be considered as the outer-most layer of this PLC project, and its input and output can be accessed by external entities.</strong>  This <code>plc_prg</code> is written in <strong>Function Block Diagram</strong> language;</li><li><code>Res0</code> : this unit contains the configuration of the whole project, for example the iteration of each iteration of the execution loop.</li></ol><p><img src="https://img.wanderingray.com/posts/multi_lan_example/evvy3l0z39un0ntu2p.png" alt="the program"/><br/>The input of this application is the <code>Reset</code> bool signal, from this example the reset is the input to all the <code>Counter%%%</code> function block. What the <code>Counter%%%</code> does is to generate an incrementing integer value at each cycle of the PLC program, the only difference is that from the suffix the the name.</p><p>Take a look at <code>CounterST</code>, <code> CounterIL</code> and <code> CounterLD</code> for example, they all implement the same function, which is defining the  <code>Reset</code> as an input and generating an incrementing integer as the output, however depending on the difference between the chosen languages, there might be some slight difference in the generated C code in <code>POUS.c</code>. These differences might seem subtle at this stage, however suppose we attempt to generate FMUs using these different implementations, the differences between them could potentially also lead to different details of the FMU structure or different behaviors within the FMUs.</p><h4 id="counterst">CounterST</h4><p><img src="https://img.wanderingray.com/posts/multi_lan_example/t9babi027iyfpxiaiv.png" alt="CounterST"/></p><h4 id="counteril">CounterIL</h4><p><img src="https://img.wanderingray.com/posts/multi_lan_example/6v1359muwfyycci76j.png" alt="CounterIL"/></p><h4 id="counterld">CounterLD</h4><p><img src="https://img.wanderingray.com/posts/multi_lan_example/iq3mnrtlpk5ua24fin.png" alt="CounterLD"/></p><h3 id="difference-in-c-code-generated-in-pousc">Difference in C code generated in <code>POUS.c</code></h3><p>The generated code for <code>instruction list</code> and <code>structural text</code> are rather simple, the XML markup for these 2 examples are represented as formatted text based on XHTML[3].</p><p><code>CounterST</code>:</p><p>Corresponding node in <code>plc.xml</code>:</p><pre class="language-xml lang-xml"><code class="language-xml lang-xml">&lt;pou name=&quot;CounterST&quot; pouType=&quot;functionBlock&quot;&gt;
        &lt;interface&gt;
          &lt;inputVars&gt;
            &lt;variable name=&quot;Reset&quot;&gt;
              &lt;type&gt;
                &lt;BOOL/&gt;
              &lt;/type&gt;
            &lt;/variable&gt;
          &lt;/inputVars&gt;
          &lt;localVars&gt;
            &lt;variable name=&quot;Cnt&quot;&gt;
              &lt;type&gt;
                &lt;INT/&gt;
              &lt;/type&gt;
            &lt;/variable&gt;
          &lt;/localVars&gt;
          &lt;outputVars&gt;
            &lt;variable name=&quot;OUT&quot;&gt;
              &lt;type&gt;
                &lt;INT/&gt;
              &lt;/type&gt;
            &lt;/variable&gt;
          &lt;/outputVars&gt;
          &lt;externalVars constant=&quot;true&quot;&gt;
            &lt;variable name=&quot;ResetCounterValue&quot;&gt;
              &lt;type&gt;
                &lt;INT/&gt;
              &lt;/type&gt;
            &lt;/variable&gt;
          &lt;/externalVars&gt;
        &lt;/interface&gt;
        &lt;body&gt;
          &lt;ST&gt;
            &lt;xhtml:p&gt;&lt;![CDATA[IF Reset THEN
  Cnt := ResetCounterValue;
ELSE
  Cnt := Cnt + 1;
END_IF;

Out := Cnt;]]&gt;&lt;/xhtml:p&gt;
          &lt;/ST&gt;
        &lt;/body&gt;
      &lt;/pou&gt;
</code></pre>
<p>The generated C code:</p><pre class="language-c lang-c"><code class="language-c lang-c">void COUNTERST_init__(COUNTERST *data__, BOOL retain) {
  __INIT_VAR(data__-&gt;EN,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__-&gt;ENO,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__-&gt;RESET,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__-&gt;CNT,0,retain)
  __INIT_VAR(data__-&gt;OUT,0,retain)
  __INIT_EXTERNAL(INT,RESETCOUNTERVALUE,data__-&gt;RESETCOUNTERVALUE,retain)
}


// Code part
void COUNTERST_body__(COUNTERST *data__) {
  // Control execution
  if (!__GET_VAR(data__-&gt;EN)) {
    __SET_VAR(data__-&gt;,ENO,,__BOOL_LITERAL(FALSE));
    return;
  }
  else {
    __SET_VAR(data__-&gt;,ENO,,__BOOL_LITERAL(TRUE));
  }
  // Initialise TEMP variables

  if (__GET_VAR(data__-&gt;RESET,)) {
    __SET_VAR(data__-&gt;,CNT,,__GET_EXTERNAL(data__-&gt;RESETCOUNTERVALUE,));
  } else {
    __SET_VAR(data__-&gt;,CNT,,(__GET_VAR(data__-&gt;CNT,) + 1));
  };
  __SET_VAR(data__-&gt;,OUT,,__GET_VAR(data__-&gt;CNT,));

  goto __end;

__end:
  return;
} // COUNTERST_body__() 
</code></pre>
<p><code>CounterIL</code>:</p><p>Corresponding node in <code>plc.xml</code>:</p><pre class="language-xml lang-xml"><code class="language-xml lang-xml">      &lt;pou name=&quot;CounterIL&quot; pouType=&quot;functionBlock&quot;&gt;
        &lt;interface&gt;
          &lt;localVars&gt;
            &lt;variable name=&quot;Cnt&quot;&gt;
              &lt;type&gt;
                &lt;INT/&gt;
              &lt;/type&gt;
            &lt;/variable&gt;
          &lt;/localVars&gt;
          &lt;inputVars&gt;
            &lt;variable name=&quot;Reset&quot;&gt;
              &lt;type&gt;
                &lt;BOOL/&gt;
              &lt;/type&gt;
            &lt;/variable&gt;
          &lt;/inputVars&gt;
          &lt;outputVars&gt;
            &lt;variable name=&quot;OUT&quot;&gt;
              &lt;type&gt;
                &lt;INT/&gt;
              &lt;/type&gt;
            &lt;/variable&gt;
          &lt;/outputVars&gt;
          &lt;externalVars constant=&quot;true&quot;&gt;
            &lt;variable name=&quot;ResetCounterValue&quot;&gt;
              &lt;type&gt;
                &lt;INT/&gt;
              &lt;/type&gt;
            &lt;/variable&gt;
          &lt;/externalVars&gt;
        &lt;/interface&gt;
        &lt;body&gt;
          &lt;IL&gt;
            &lt;xhtml:p&gt;&lt;![CDATA[LD Reset
JMPC ResetCnt

(* increment counter *)
LD Cnt
ADD 1
JMP QuitFb

ResetCnt:
(* reset counter *)
LD ResetCounterValue

QuitFb:
(* save results *)
ST Cnt
ST Out
]]&gt;&lt;/xhtml:p&gt;
          &lt;/IL&gt;
        &lt;/body&gt;
      &lt;/pou&gt;
</code></pre>
<pre class="language-c lang-c"><code class="language-c lang-c">void COUNTERIL_init__(COUNTERIL *data__, BOOL retain) {
  __INIT_VAR(data__-&gt;EN,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__-&gt;ENO,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__-&gt;CNT,0,retain)
  __INIT_VAR(data__-&gt;RESET,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__-&gt;OUT,0,retain)
  __INIT_EXTERNAL(INT,RESETCOUNTERVALUE,data__-&gt;RESETCOUNTERVALUE,retain)
}

// Code part
void COUNTERIL_body__(COUNTERIL *data__) {
  // Control execution
  if (!__GET_VAR(data__-&gt;EN)) {
    __SET_VAR(data__-&gt;,ENO,,__BOOL_LITERAL(FALSE));
    return;
  }
  else {
    __SET_VAR(data__-&gt;,ENO,,__BOOL_LITERAL(TRUE));
  }
  // Initialise TEMP variables

  __IL_DEFVAR_T __IL_DEFVAR;
  __IL_DEFVAR_T __IL_DEFVAR_BACK;
  __IL_DEFVAR.BOOLvar = __GET_VAR(data__-&gt;RESET,);
  if (__IL_DEFVAR.BOOLvar) goto RESETCNT;
  __IL_DEFVAR.INTvar = __GET_VAR(data__-&gt;CNT,);
  __IL_DEFVAR.INTvar += 1;
  goto QUITFB;
  RESETCNT:
  ;
  __IL_DEFVAR.INTvar = __GET_EXTERNAL(data__-&gt;RESETCOUNTERVALUE,);
  QUITFB:
  ;
  __SET_VAR(data__-&gt;,CNT,,__IL_DEFVAR.INTvar);
  __SET_VAR(data__-&gt;,OUT,,__IL_DEFVAR.INTvar);

  goto __end;

__end:
  return;
} // COUNTERIL_body__() 
</code></pre>
<p>And <code>CouterLD</code>, the generated C code of the ladder diagram representation has more inline functions in the initialization part, they are corresponding to the blocks in the ladder diagram, which works as smaller function units within this module:</p><pre class="language-c lang-c"><code class="language-c lang-c">static inline INT __COUNTERLD_ADD__INT__INT1(BOOL EN,
  UINT __PARAM_COUNT,
  INT IN1,
  INT IN2,
  COUNTERLD *data__)
{
  INT __res;
  BOOL __TMP_ENO = __GET_VAR(data__-&gt;_TMP_ADD11_ENO,);
  __res = ADD__INT__INT(EN,
    &amp;__TMP_ENO,
    __PARAM_COUNT,
    IN1,
    IN2);
  __SET_VAR(,data__-&gt;_TMP_ADD11_ENO,,__TMP_ENO);
  return __res;
}

static inline INT __COUNTERLD_MOVE__INT__INT2(BOOL EN,
  INT IN,
  COUNTERLD *data__)
{
  INT __res;
  BOOL __TMP_ENO = __GET_VAR(data__-&gt;_TMP_MOVE15_ENO,);
  __res = MOVE__INT__INT(EN,
    &amp;__TMP_ENO,
    IN);
  __SET_VAR(,data__-&gt;_TMP_MOVE15_ENO,,__TMP_ENO);
  return __res;
}

static inline INT __COUNTERLD_MOVE__INT__INT3(BOOL EN,
  INT IN,
  COUNTERLD *data__)
{
  INT __res;
  BOOL __TMP_ENO = __GET_VAR(data__-&gt;_TMP_MOVE19_ENO,);
  __res = MOVE__INT__INT(EN,
    &amp;__TMP_ENO,
    IN);
  __SET_VAR(,data__-&gt;_TMP_MOVE19_ENO,,__TMP_ENO);
  return __res;
}

void COUNTERLD_init__(COUNTERLD *data__, BOOL retain) {
  __INIT_VAR(data__-&gt;EN,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__-&gt;ENO,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__-&gt;RESET,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__-&gt;OUT,0,retain)
  __INIT_VAR(data__-&gt;CNT,0,retain)
  __INIT_EXTERNAL(INT,RESETCOUNTERVALUE,data__-&gt;RESETCOUNTERVALUE,retain)
  __INIT_VAR(data__-&gt;_TMP_ADD11_ENO,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__-&gt;_TMP_ADD11_OUT,0,retain)
  __INIT_VAR(data__-&gt;_TMP_MOVE15_ENO,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__-&gt;_TMP_MOVE15_OUT,0,retain)
  __INIT_VAR(data__-&gt;_TMP_MOVE19_ENO,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__-&gt;_TMP_MOVE19_OUT,0,retain)
}

// Code part
void COUNTERLD_body__(COUNTERLD *data__) {
  // Control execution
  if (!__GET_VAR(data__-&gt;EN)) {
    __SET_VAR(data__-&gt;,ENO,,__BOOL_LITERAL(FALSE));
    return;
  }
  else {
    __SET_VAR(data__-&gt;,ENO,,__BOOL_LITERAL(TRUE));
  }
  // Initialise TEMP variables

  __SET_VAR(data__-&gt;,_TMP_ADD11_OUT,,__COUNTERLD_ADD__INT__INT1(
    (BOOL)__BOOL_LITERAL(TRUE),
    (UINT)2,
    (INT)__GET_VAR(data__-&gt;CNT,),
    (INT)1,
    data__));
  if (__GET_VAR(data__-&gt;_TMP_ADD11_ENO,)) {
    __SET_VAR(data__-&gt;,CNT,,__GET_VAR(data__-&gt;_TMP_ADD11_OUT,));
  };
  __SET_VAR(data__-&gt;,_TMP_MOVE15_OUT,,__COUNTERLD_MOVE__INT__INT2(
    (BOOL)__GET_VAR(data__-&gt;RESET,),
    (INT)__GET_EXTERNAL(data__-&gt;RESETCOUNTERVALUE,),
    data__));
  if (__GET_VAR(data__-&gt;_TMP_MOVE15_ENO,)) {
    __SET_VAR(data__-&gt;,CNT,,__GET_VAR(data__-&gt;_TMP_MOVE15_OUT,));
  };
  __SET_VAR(data__-&gt;,_TMP_MOVE19_OUT,,__COUNTERLD_MOVE__INT__INT3(
    (BOOL)__BOOL_LITERAL(TRUE),
    (INT)__GET_VAR(data__-&gt;CNT,),
    data__));
  if (__GET_VAR(data__-&gt;_TMP_MOVE19_ENO,)) {
    __SET_VAR(data__-&gt;,OUT,,__GET_VAR(data__-&gt;_TMP_MOVE19_OUT,));
  };

  goto __end;

__end:
  return;
} // COUNTERLD_body__() 
</code></pre>
<h3 id="remaining-and-new-questions--problems">Remaining and new questions &amp; problems</h3><ol start="1"><li>Is the compiled .so library files able to be executed on actual devices? Is it executed well in local simulator / development runtime environment?</li><li>How exactly is the compilation process executed? Is it possible to expose some internal variables or input to external entities? To what degree is the whole program configurable?</li><li><strong>How EXACTLY is the simulation process executed?</strong> Understanding this could be extremely crucial for creating FMU for OSP sw. (TODO: Look into OpenPLC runtime)</li><li><strong>[NEW]</strong> This example hasn&#x27;t defined any address mapping ( for any specific hardware platform ), how necessary is it to find out &amp; what are the proper steps of doing this?</li><li><strong>*[NEW]</strong> I noticed the XSLT (eXtensible Stylesheet Language Transformations) in the PLCOpen XML&#x27;s technical paper, it&#x27;s purpose is to transform the XML provided by some specific vendor / supplier to the PLCOpen XML format that can be utilized by development tools such as OpenPLC. However I haven&#x27;t figured out the priority / importance of learning more about this tool.*</li><li><strong>[NEW]</strong> Is it possible to remove the libraries related to OpenPLC runtime, and then build the stand-along executable PLC program?</li></ol><h3 id="next-steps">Next Steps</h3><ol start="1"><li>Understand the OpenPLC Runtime Code;</li><li>Look at the Compilation Output;</li><li><strong>Look into &amp; Integrate with the FMI &amp; FMU Standard;</strong></li><li><strong>Is it possible to remove the libraries related to OpenPLC runtime, and then build the stand-along executable PLC program?</strong></li></ol><h3 id="references">References</h3><ol start="1"><li><a href="https://beremiz.org/doc">The documentation page of <code>Beremiz</code> has some descriptions about the compiling process. (https://beremiz.org/doc)</a></li><li><a href="https://plcopen.org/system/files/downloads/tc6_xml_v201_technical_doc.pdf">Technical Paper PLCopen Technical Committee 6 : XML Formats for IEC 61131-3, Version 2.01 - Official release</a></li><li><a href="https://plcopen.org/system/files/downloads/tc6_xml_v201_technical_doc.pdf">Technical Paper PLCopen Technical Committee 6 : XML Formats for IEC 61131-3, Version 2.01 - Official release, chapter 6.6</a></li><li><a href="https://beckassets.blob.core.windows.net/product/readingsample/684471/9783642120145_excerpt_001.pdf">IEC 61131-3: Programming Industrial Automation Systems (Sample Chapter)</a></li></ol></div><p style="text-align:right"><a href="https://wanderingray.com/posts/	research/multiple_language_example_in_OpenPLC#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/posts/	research/multiple_language_example_in_OpenPLC</link><guid isPermaLink="true">https://wanderingray.com/posts/	research/multiple_language_example_in_OpenPLC</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Thu, 10 Oct 2024 16:33:58 GMT</pubDate></item><item><title><![CDATA[Arduino print serial text (Ladder Diagram) exapmple]]></title><description><![CDATA[<link rel="preload" as="image" href="https://img.wanderingray.com/posts/arduino_serial_text_exmpl/bhjlkk400lrbaipbgg.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/arduino_serial_text_exmpl/pjn4892q6laj0d8uxm.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/arduino_serial_text_exmpl/jry1sg2tvrqbf3b6p9.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/posts/arduino_serial_text_exmpl/sox5j2v15iz204rqi6.png"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/posts/	research/arduino_printmsg_example">https://wanderingray.com/posts/	research/arduino_printmsg_example</a></blockquote><div><p>Still trying to get familiar with PLC programming (using OpenPLC), I started with some examples:</p><h3 id="ladder-diagram-on-openplc-arduino-uno-as-the-device">Ladder Diagram on OpenPLC (Arduino Uno as the device)</h3><p>Some introductions about basic syntax and examples are on <a href="https://en.wikipedia.org/wiki/Ladder_logic">wikipedia</a>, and here&#x27;s an example project in OpenPLC editor, which is outputting a line of text through the serial port at the same frequence of LED blink.t</p><p>This is how the LD program looks like:<br/><img src="https://img.wanderingray.com/posts/arduino_serial_text_exmpl/bhjlkk400lrbaipbgg.png" alt="Blink LD program"/><br/>There are mainly 3 parts.<br/><img src="https://img.wanderingray.com/posts/arduino_serial_text_exmpl/pjn4892q6laj0d8uxm.png" alt="Part 1: timer + relay"/><br/>This part defines the interval / frequency of LED blink. On the left there is an rung input ( or &quot;checkercontact&quot; in ladder diagrams) <code>—[ ]—</code> , it&#x27;s taking the on-board LED&#x27;s status as an input. <code>TON0</code> and <code>TOF0</code> are timer relays, what they do is to generate a high of low voltage output at the <code>Q</code> end according to the preset time duration.<br/><img src="https://img.wanderingray.com/posts/arduino_serial_text_exmpl/jry1sg2tvrqbf3b6p9.png" alt="rising edge enable PrintMSG"/><br/>This part is using the <strong>rising edge</strong> of the LED pin to enable the PrintMSG function,<br/><img src="https://img.wanderingray.com/posts/arduino_serial_text_exmpl/sox5j2v15iz204rqi6.png" alt="Providing string literal to the PrintMSG function"/><br/>And eventually the message printing process is an arithmetic operation called <code>MOVE</code> , what it does is to copy the string literal from <code>in</code> pin to an external variable called <code>SerialMSG</code> on the <code>OUT</code> pin.</p><p>It still looks a bit confusing at this point, but there&#x27;s also the Arduino side of the program:</p><pre class="language-c lang-c"><code class="language-c lang-c">//////////////////////////////// sketch section ////////////////////////////////


// This is the Arduino side of the project. The functions sketch_setup() and
// sketch_loop() provide the same functionality of the setup() and loop()
// functions of a regular Arduino sketch. On top of this code editor there is a
// variable table. You can add variables there that are shared between the 
// arduino code and the PLC code. Since they are shared, you can, for example,
// read a sensor on the arduino sketch and use the reading in a PLC program. 
// On the PLC side you must declare the same variable with the class &quot;external&quot;
// before being able to use it in your program.

// This Arduino sketch implementation is compatible with virtually every library
// or code you can possibly run on the regular Arduino IDE. You can create your
// own functions and also #include external libraries (as long as they are also
// installed on your Arduino IDE). The only catch is that your sketch_loop() 
// function cannot block (long while loop or delays), or else your PLC code will
// block as well.

// Notes about this particular demo: Since this demo uses the serial port, you
// cannot enable Modbus Serial on your project, otherwise it will conflict with
// the messages being printed from this sketch. Also, this sketch shares a
// STRING with the PLC side. This is not a regular c-string, it is an IEC 61131
// STRING. Variables shared between the PLC and Arduino sketch are always IEC
// 61131 variables. For normal datatypes like INT, REAL, DINT, etc, there are
// direct equivalents in C (int16_t, float and int32_t respectively), so you
// shouldn&#x27;t have any problems with those. An IEC STRING however is a more 
// complex structure. You can typecast an IEC STRING into a c-string by using 
// (char *)STRING.body as shown in the example below.

void sketch_setup()
{
    Serial.begin(115200);
    Serial.println(&quot;Hello World! I&#x27;m starting now...&quot;);
}

void sketch_loop()
{
    if (PrintMSG)
    {
        Serial.println((char *)SerialMSG.body);
    }
}
</code></pre>
<p>In this case, it&#x27;s using the variables ( <code> PrintMSG</code> and <code> SerialMSG</code> ) modified in the ladder diagram in the <code>sketch_loop</code> function.</p><h3 id="the-output-files-of-openplc-compiling-process">The output files of OpenPLC compiling process</h3><p>When the program is being build, there would be some .obj and lib files generated:</p><pre class=""><code class="">Start build in /home/ray/Downloads/OpenPLC Editor for Linux/OpenPLC_Editor/editor/examples/Arduino_Serial_Print/build
Generating SoftPLC IEC-61131 ST/IL/SFC code...
    Collecting data types
    Collecting POUs
    Generate POU ArduinoPrint
    Generate Config(s)
Compiling IEC Program into C code...
Extracting Located Variables...
C code generated successfully.
PLC :
   [CC]  plc_main.c -&gt; plc_main.o
   [CC]  plc_debugger.c -&gt; plc_debugger.o
PLC :
   [CC]  Config0.c -&gt; Config0.o
   [CC]  Res0.c -&gt; Res0.o
0 :
   [CC]  CFile_0.c -&gt; CFile_0.o
Linking :
   [CC]  plc_main.o plc_debugger.o Config0.o Res0.o CFile_0.o -&gt; Arduino_Serial_Print.so
Successfully built.
Build MD5: 4e8dd5085880b489b8a48c8bf30f9588
</code></pre>
<p>And actually the Arduino code in the previous section is in <code>CFile_0.c</code>:</p><pre class="language-c lang-c"><code class="language-c lang-c">/* Code generated by Beremiz c_ext confnode */

#ifdef ARDUINO_PLATFORM

#include &lt;stdio.h&gt;
#include &quot;iec_types_all.h&quot;

/* User variables reference */
extern &quot;C&quot; __IEC_STRING_t CONFIG0__SERIALMSG;
#define SerialMSG CONFIG0__SERIALMSG.value
extern &quot;C&quot; __IEC_BOOL_t CONFIG0__PRINTMSG;
#define PrintMSG CONFIG0__PRINTMSG.value

/* User sketch */
// This is the Arduino side of the project. The functions sketch_setup() and
// sketch_loop() provide the same functionality of the setup() and loop()
// functions of a regular Arduino sketch. On top of this code editor there is a
// variable table. You can add variables there that are shared between the 
// arduino code and the PLC code. Since they are shared, you can, for example,
// read a sensor on the arduino sketch and use the reading in a PLC program. 
// On the PLC side you must declare the same variable with the class &quot;external&quot;
// before being able to use it in your program.

// This Arduino sketch implementation is compatible with virtually every library
// or code you can possibly run on the regular Arduino IDE. You can create your
// own functions and also #include external libraries (as long as they are also
// installed on your Arduino IDE). The only catch is that your sketch_loop() 
// function cannot block (long while loop or delays), or else your PLC code will
// block as well.

// Notes about this particular demo: Since this demo uses the serial port, you
// cannot enable Modbus Serial on your project, otherwise it will conflict with
// the messages being printed from this sketch. Also, this sketch shares a
// STRING with the PLC side. This is not a regular c-string, it is an IEC 61131
// STRING. Variables shared between the PLC and Arduino sketch are always IEC
// 61131 variables. For normal datatypes like INT, REAL, DINT, etc, there are
// direct equivalents in C (int16_t, float and int32_t respectively), so you
// shouldn&#x27;t have any problems with those. An IEC STRING however is a more 
// complex structure. You can typecast an IEC STRING into a c-string by using 
// (char *)STRING.body as shown in the example below.

void sketch_setup()
{
    Serial.begin(115200);
    Serial.println(&quot;Hello World! I&#x27;m starting now...&quot;);
}

void sketch_loop()
{
    if (PrintMSG)
    {
        Serial.println((char *)SerialMSG.body);
    }
}
#endif

</code></pre>
<p>And the Ladder Diagram was translated into C files first, it&#x27;s in a file called <code>POUS.c</code>:</p><pre class="language-c lang-c"><code class="language-c lang-c">void LOGGER_init__(LOGGER *data__, BOOL retain) {
  __INIT_VAR(data__-&gt;EN,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__-&gt;ENO,__BOOL_LITERAL(TRUE),retain)
  __INIT_VAR(data__-&gt;TRIG,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__-&gt;MSG,__STRING_LITERAL(0,&quot;&quot;),retain)
  __INIT_VAR(data__-&gt;LEVEL,LOGLEVEL__INFO,retain)
  __INIT_VAR(data__-&gt;TRIG0,__BOOL_LITERAL(FALSE),retain)
}

// Code part
void LOGGER_body__(LOGGER *data__) {
  // Control execution
  if (!__GET_VAR(data__-&gt;EN)) {
    __SET_VAR(data__-&gt;,ENO,,__BOOL_LITERAL(FALSE));
    return;
  }
  else {
    __SET_VAR(data__-&gt;,ENO,,__BOOL_LITERAL(TRUE));
  }
  // Initialise TEMP variables

  if ((__GET_VAR(data__-&gt;TRIG,) &amp;&amp; !(__GET_VAR(data__-&gt;TRIG0,)))) {
    #define GetFbVar(var,...) __GET_VAR(data__-&gt;var,__VA_ARGS__)
    #define SetFbVar(var,val,...) __SET_VAR(data__-&gt;,var,__VA_ARGS__,val)

   LogMessage(GetFbVar(LEVEL),(char*)GetFbVar(MSG, .body),GetFbVar(MSG, .len));
  
    #undef GetFbVar
    #undef SetFbVar
;
  };
  __SET_VAR(data__-&gt;,TRIG0,,__GET_VAR(data__-&gt;TRIG,));

  goto __end;

__end:
  return;
} // LOGGER_body__() 





static inline STRING __ARDUINOPRINT_MOVE__STRING__STRING1(BOOL EN,
  STRING IN,
  ARDUINOPRINT *data__)
{
  STRING __res;
  BOOL __TMP_ENO = __GET_VAR(data__-&gt;_TMP_MOVE14_ENO,);
  __res = MOVE__STRING__STRING(EN,
    &amp;__TMP_ENO,
    IN);
  __SET_VAR(,data__-&gt;_TMP_MOVE14_ENO,,__TMP_ENO);
  return __res;
}

void ARDUINOPRINT_init__(ARDUINOPRINT *data__, BOOL retain) {
  __INIT_LOCATED(BOOL,__QX0_3,data__-&gt;BLINK_LED,retain)
  __INIT_LOCATED_VALUE(data__-&gt;BLINK_LED,__BOOL_LITERAL(FALSE))
  TON_init__(&amp;data__-&gt;TON0,retain);
  TOF_init__(&amp;data__-&gt;TOF0,retain);
  __INIT_EXTERNAL(STRING,SERIALMSG,data__-&gt;SERIALMSG,retain)
  __INIT_EXTERNAL(BOOL,PRINTMSG,data__-&gt;PRINTMSG,retain)
  R_TRIG_init__(&amp;data__-&gt;R_TRIG1,retain);
  __INIT_VAR(data__-&gt;_TMP_MOVE14_ENO,__BOOL_LITERAL(FALSE),retain)
  __INIT_VAR(data__-&gt;_TMP_MOVE14_OUT,__STRING_LITERAL(0,&quot;&quot;),retain)
}

// Code part
void ARDUINOPRINT_body__(ARDUINOPRINT *data__) {
  // Initialise TEMP variables

  __SET_VAR(data__-&gt;TON0.,EN,,__BOOL_LITERAL(TRUE));
  __SET_VAR(data__-&gt;TON0.,IN,,!(__GET_LOCATED(data__-&gt;BLINK_LED,)));
  __SET_VAR(data__-&gt;TON0.,PT,,__time_to_timespec(1, 500, 0, 0, 0, 0));
  TON_body__(&amp;data__-&gt;TON0);
  __SET_VAR(data__-&gt;TOF0.,EN,,__GET_VAR(data__-&gt;TON0.ENO,));
  __SET_VAR(data__-&gt;TOF0.,IN,,__GET_VAR(data__-&gt;TON0.Q,));
  __SET_VAR(data__-&gt;TOF0.,PT,,__time_to_timespec(1, 500, 0, 0, 0, 0));
  TOF_body__(&amp;data__-&gt;TOF0);
  __SET_LOCATED(data__-&gt;,BLINK_LED,,__GET_VAR(data__-&gt;TOF0.Q,));
  __SET_VAR(data__-&gt;R_TRIG1.,CLK,,__GET_LOCATED(data__-&gt;BLINK_LED,));
  R_TRIG_body__(&amp;data__-&gt;R_TRIG1);
  __SET_EXTERNAL(data__-&gt;,PRINTMSG,,__GET_VAR(data__-&gt;R_TRIG1.Q,));
  __SET_VAR(data__-&gt;,_TMP_MOVE14_OUT,,__ARDUINOPRINT_MOVE__STRING__STRING1(
    (BOOL)__BOOL_LITERAL(TRUE),
    (STRING)__STRING_LITERAL(28,&quot;this is a string from ladder&quot;),
    data__));
  if (__GET_VAR(data__-&gt;_TMP_MOVE14_ENO,)) {
    __SET_EXTERNAL(data__-&gt;,SERIALMSG,,__GET_VAR(data__-&gt;_TMP_MOVE14_OUT,));
  };

  goto __end;

__end:
  return;
} // ARDUINOPRINT_body__() 
</code></pre>
<p>The <code>ARDUINOPRINT_body__()</code> contains the corresponding ladder diagram operations.</p><h3 id="problems">Problems</h3><p>Is the compiled .so library files able to be executed on actual devices? Is it executed well in local simulator / development runtime environment?</p><p>How exactly is the compilation process executed? Is it possible to expose some internal variables or input to external entities? To what degree is the whole program configurable?</p><p>What are the possible limits for PLC programs ( if the developers want to create FMUs for these programs )? For example if some variables are supposed to be accessable by external entities rather than being private withing the FMU, would there be a guideline / to-do / not-to-do list for for the PLC programs?</p><h3 id="next-steps">Next Steps</h3><ol start="1"><li>Try to run the example project on simulator, just to make sure it works.</li><li>Check about different examples, including different languages in IEC 61131-3 and examples that are supposed to run on other PLC devices, pay attention to whether or not there are differences in generated C code.</li></ol></div><p style="text-align:right"><a href="https://wanderingray.com/posts/	research/arduino_printmsg_example#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/posts/	research/arduino_printmsg_example</link><guid isPermaLink="true">https://wanderingray.com/posts/	research/arduino_printmsg_example</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Thu, 19 Sep 2024 16:23:24 GMT</pubDate></item><item><title><![CDATA[Research topic: creating FMU from PLC programs]]></title><description><![CDATA[<link rel="preload" as="image" href="https://img.wanderingray.com/posts/research_topic_plc_fmu/bz43vfoe4fk6xwdmrq.png"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/posts/	research/Research-topic%3A-creating-FMU-from-PLC-programs">https://wanderingray.com/posts/	research/Research-topic%3A-creating-FMU-from-PLC-programs</a></blockquote><div><h2 id="initial-look-into-the-topic-materials-and-my-thoughts">Initial look into the topic materials and my thoughts</h2><p>I have looked into the materials and asked ChatGPT to get some deeper understanding of the topic ( may or may not be accurate ), I think it would be a good practice to document them down before I forget about everything after I wake up overnight.</p><p>I&#x27;m mainly trying to have a general understanding about the <em>tools involved</em>, <em>goals</em> and possible <em>roadmap of approaching the goals</em>, as well as some possible <em>challenges</em> that I can think of.</p><h3 id="plc-programming-and-iec-61131-3">PLC programming and IEC 61131-3</h3><p>I spent some time learning about <code>IEC 6113-3</code> before, basically it defines some textual and graphical programming languages ( namely <code>Ladder diagram (LD, graphical)</code>, <code>Function block diagram (FBD, graphical)</code>, <code>Structured text (ST, textual)</code>, <code>Instruction list (IL, textual)</code> and <code>Sequential function chart (SFC, graphical)</code> ) for the control program in PLC.<br/>Taking <a href="https://autonomylogic.com/">OpenPLC</a> for example, it contains an editor that allows developers to edit the source files in these languages and then using the <a href="https://github.com/nucleron/matiec"><code>MatIEC Compiler</code></a> compiles them into C code or equivalence of IEC standard code [1].<br/>In OpenPLC&#x27;s documentation, they also mentioned the <a href="https://autonomylogic.com/docs/2-1-openplc-runtime-overview/">OpenPLC Runtime</a>, which is installed on the target device where the actual PLC program is supposed to be executed. And OpenPLC also provides some built-in tools for various purposes, for example to configure the parameters of the runtime, uploading programs etc.
For other PLC development tools, the process should be more or less similar.</p><h3 id="fmi-standard-and-fmu">FMI standard and FMU</h3><p>I have only glanced through the FMI 3.0 overview slides and it&#x27;s a bit overwhelming, but basically now I know that FMU is a cross-language simulation unit, namely a compressed file ends with <code>.fmu</code>, which contains mainly 2 types of content and some optional contents:<br/><img src="https://img.wanderingray.com/posts/research_topic_plc_fmu/bz43vfoe4fk6xwdmrq.png" alt="FMU layout example" height="700" width="553"/></p><ol start="1"><li><code>modelDescription.xml</code>: some descriptive information about the model being exported into as FMU;</li><li>Model representation: binaries ( executables or libraries for one or many platforms ), or maybe source code;</li><li><p>Optionals: icons, documentations, port definition, resources etc...</p><p>There&#x27;s tons of tools and resources related to this, definitely going to be helpful after sorting them out.</p><h3 id="open-simulation-platform-osp">Open Simulation Platform (OSP)</h3><p>Also I had only glanced through the slides, from my understanding it&#x27;s a platform / tool set that can take in multiple FMUs from various sources and operate some integrated simulation.</p><h2 id="goals">Goals</h2><p>The goal is to figure out how to export the PLC program into FMU, alternatively if the PLC development tool comes from some vendors that has their own proprietary binaries or runtime, is there a way to wrap up the whole PLC program alongside with these dependencies and export them into FMUs.</p><h2 id="possible-roadmap">Possible roadmap</h2></li><li>Get familiar with some PLC development tools, as well as the process of running PLC programs on the runtime / target devices;</li><li>Get familiar with FMI standard and FMU generation, get some hands-on experience on creating FMU from existing demo models;</li><li>Get familiar with eh OSP co-simulation software;</li><li><p>During the process above, investigate into possible solutions to the goal.</p><h2 id="some-difficulties-or-challenges--that-i-can-think-of-">Some difficulties or challenges ( that I can think of )</h2></li><li>I personally have no experience directly programming with PLC development tools, nor did I have tried anything related to simulations, these might take me some time to familiarize;</li><li><p>Due to my unfamiliarity to the related concepts, sometimes it might be quite tricky to come up with the proper questions. And the documentations and tools are quite overwhelming, it would be helpful if I&#x27;m able to consult someone with more experience in it to get some guidance;</p><h2 id="questions">Questions</h2><p>In the FMI 3.0 overview slides they introduced FMU for <code>model exchange</code> and <code>co-simulation</code>, I don&#x27;t know much about simulation but according to what I read, both of them are some sort of <strong>ordinary differential equations (ODEs) with events</strong> ( I assume this is the mathematic models to describe some features of real-world hardware ), and they also need a <strong>solver</strong> ( should be a program that generate <strong>discrete values</strong> based on one specific input to the models ), the main difference between these 2 seems to be how the solver is incorporated into the FMUs.<br/>So my questions is, does it mean these simulation models are kind of like the &quot;intermediate results&quot; of PLC programs?
From my understanding, the PLC program defines the behavior of the runtime / physical devices that are going to execute them, and these simulations are probably a form of representation of the physical devices, but the connections between these two seem to be complicated.</p><h2 id="side-notes-and-concepts-that-might-be-related-or-not">Side notes and concepts that might be related (or not)</h2><blockquote><p>industrial automation layers</p></blockquote>
</li></ol><h2 id="references">References</h2><p>: documentations about the MatIEC compilers;</p></div><p style="text-align:right"><a href="https://wanderingray.com/posts/	research/Research-topic%3A-creating-FMU-from-PLC-programs#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/posts/	research/Research-topic%3A-creating-FMU-from-PLC-programs</link><guid isPermaLink="true">https://wanderingray.com/posts/	research/Research-topic%3A-creating-FMU-from-PLC-programs</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Thu, 12 Sep 2024 16:13:10 GMT</pubDate></item><item><title><![CDATA[Yet another horrifying "Perfect Murder"]]></title><description><![CDATA[<link rel="preload" as="image" href="https://img.wanderingray.com/notes/chick_murder_cop_again/19yg5p94gnc1qm0uc5.png"/><link rel="preload" as="image" href="https://img.wanderingray.com/notes/chick_murder_cop_again/vsomdgf4s1va6aojvt.jpg"/><link rel="preload" as="image" href="https://img.wanderingray.com/notes/chick_murder_cop_again/233xp7v8o12wfr9pz4.jpeg"/><div><blockquote>该渲染由 Shiro API 生成，可能存在排版问题，最佳体验请前往：<a href="https://wanderingray.com/notes/3">https://wanderingray.com/notes/3</a></blockquote><div><p>In China, just last year in Chengdu, Sichuan, there was a case where a 16-year-old boy was lured into the water by two women to save a dog and drowned, and the two women received no punishment. And now, more recently, there has been an even more heinous case of a woman pretending to commit suicide by drowning and deliberately killing Officer Li Xie. Footage from the scene clearly shows that the woman <strong>had strong swimming skills</strong>. While <strong>maintaining a backstroke position to keep her head above water and breathe stably</strong>, she <strong>deliberately pressed the police officer’s head down</strong>, and <strong>twice grabbed the officer’s lifeline and pushed him away</strong>, ultimately resulting in the officer&#x27;s death. (<a href="https://www.thepaper.cn/newsDetail_forward_28525080">Pengpai News: &quot;Heartbreaking! A police officer in Guangxi tragically sacrificed his life while rescuing a drowning person, and his final moments brought tears to the eyes.</a>&quot; Currently, the video from the scene can still be found on WeChat public accounts.)<br/>Of course, it&#x27;s highly likely there will be no punishment. In mainland China, the judicial system often abuses discretionary powers, and the leniency shown to female offenders, even in cases of serious violent crime, is unmatched globally—a fact that has become increasingly evident to the public in recent years.<br/>If you live in mainland China, it&#x27;s best to educate your daughters to protect themselves, and also to teach your sons not to offer help lightly, especially to young women. After all, life only comes once, and sometimes it’s necessary to be suspicious of certain irrational women with the greatest malice.<br/>I know my views will likely be labeled as &quot;misogynistic,&quot; but you really can&#x27;t blame people for losing their compassion. First, ask yourself, who was it that eroded that trust?</p><p><img src="https://img.wanderingray.com/notes/chick_murder_cop_again/19yg5p94gnc1qm0uc5.png" alt="In 2023, a 16-year-old boy was lured into the river and eventually drowned" height="244" width="1013"/></p><p>Translation:</p><blockquote><p>【#16-year-old boy suspected to have drowned while trying to save someone from a river, but it was actually a dog】 #16-year-old boy drowns in the river while attempting to rescue a dog# On June 20th, in Chengdu, Sichuan, a 16-year-old boy reportedly jumped into the river to save what he believed was a person after hearing cries for help. According to acquaintances, it was suspected that two women’s dog fell into the river, and the boy mistook it for a person in danger. He tragically drowned while trying to rescue what he thought was a person. The site has since been cordoned off. On the 21st, the local police reported that the boy’s body has yet to be recovered, and the exact details are pending further official investigation.</p><br/><p><img src="https://img.wanderingray.com/notes/chick_murder_cop_again/vsomdgf4s1va6aojvt.jpg" alt="Baidu Tieba netizens exposed the attack strategy of Xiaohongshu users"/></p><p>Translation:<br/>&quot;On XHS (Xiaohongshu), some women are sharing a disgusting tactic. They pretend to jump into the water and commit suicide, waiting for someone to rescue them. If the rescuer is a man, they will cling to him in the water, and eventually, they can achieve their goal without bearing any responsibility.&quot;</p><br/><p><img src="https://img.wanderingray.com/notes/chick_murder_cop_again/233xp7v8o12wfr9pz4.jpeg" alt="Xiaohongshu users publish hate speech against men and encourage murder"/></p><p>Translation:<br/>momo Some men should just go die!!<br/>Let me teach everyone a way to get back at scumbags: Go to a crowded place and pretend to jump into a river. Generally, men will feel compelled to save you, and then you can drown him in the water. Just claim that you fell into the water due to a mental disorder, and you&#x27;re good to go.<br/>Edited on 2021-04-27<br/>momo: There&#x27;s not a single good man in this world! They are all scum, even my brother. Every day he only knows how to make my mom angry. He doesn&#x27;t know how to fix a toilet, yet stays up late playing games. My mom can&#x27;t catch a break, and I have to constantly remind her not to get mad over him, yet he never changes! I hate men like him so much! They have no heart, no conscience, they are eternally selfish, never understanding anything. They&#x27;re just pigs—eating and getting fat every day without caring! They should just go die! All they do is live off others! Truly disgusting creatures! I hope they all drop dead! My brother is a total waste of space! All men deserve to die!</p></blockquote></div><p style="text-align:right"><a href="https://wanderingray.com/notes/3#comments">看完了？说点什么呢</a></p></div>]]></description><link>https://wanderingray.com/notes/3</link><guid isPermaLink="true">https://wanderingray.com/notes/3</guid><dc:creator><![CDATA[ray]]></dc:creator><pubDate>Tue, 27 Aug 2024 17:02:55 GMT</pubDate></item></channel></rss>